findUsersByUsernameNative(String username);
+}
\ No newline at end of file
diff --git a/src/main/java/top/whgojp/modules/sqli/service/HsqliService.java b/src/main/java/top/whgojp/modules/sqli/service/HsqliService.java
deleted file mode 100644
index 61dae36..0000000
--- a/src/main/java/top/whgojp/modules/sqli/service/HsqliService.java
+++ /dev/null
@@ -1,11 +0,0 @@
-//package top.whgojp.modules.sqli.service;
-//
-///**
-// * @description <功能描述>
-// * @author: whgojp
-// * @email: whgojp@foxmail.com
-// * @Date: 2024/8/5 18:11
-// */
-//public interface HsqliService {
-//
-//}
diff --git a/src/main/java/top/whgojp/modules/ssrf/controller/SsrfController.java b/src/main/java/top/whgojp/modules/ssrf/controller/SsrfController.java
index 7a3bb49..6a864f0 100644
--- a/src/main/java/top/whgojp/modules/ssrf/controller/SsrfController.java
+++ b/src/main/java/top/whgojp/modules/ssrf/controller/SsrfController.java
@@ -10,10 +10,14 @@
import org.springframework.web.bind.annotation.*;
import top.whgojp.common.utils.CheckUserInput;
+import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
+import java.io.IOException;
import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
/**
* @description SSRF-服务端请求伪造
@@ -32,6 +36,22 @@ public String fileUpload() {
return "vul/ssrf/ssrf";
}
+ @ApiOperation(value = "模拟内网元数据服务", notes = "用于SSRF场景演示,模拟攻击者通过服务端访问内网或云元数据接口")
+ @GetMapping("/internal/metadata")
+ @ResponseBody
+ public String internalMetadata() {
+ return "instance-id: i-javaseclab-ssrf\n"
+ + "role: internal-admin\n"
+ + "token: javaseclab-metadata-token\n"
+ + "source: 127.0.0.1";
+ }
+
+ @ApiOperation(value = "模拟跳转链路", notes = "用于演示SSRF修复时必须禁用自动跳转,或对每一跳重新校验")
+ @GetMapping("/redirect")
+ public void redirect(@RequestParam String target, HttpServletResponse response) throws IOException {
+ response.sendRedirect(target);
+ }
+
@ApiOperation(value = "漏洞场景:服务端请求伪造", notes = "原生漏洞场景,未做任何限制,可调用URLConnection发起任意请求,探测内网服务、读取文件")
@GetMapping("/vul")
@ResponseBody
@@ -70,8 +90,11 @@ public String safe(@ApiParam(name = "url", value = "请求参数", required = tr
} else {
try {
URL u = new URL(url);
- URLConnection conn = u.openConnection(); // 这里以URLConnection作为演示
- BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ HttpURLConnection conn = (HttpURLConnection) u.openConnection();
+ conn.setInstanceFollowRedirects(false);
+ conn.setConnectTimeout(3000);
+ conn.setReadTimeout(3000);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
String content;
StringBuilder html = new StringBuilder();
html.append("");
diff --git a/src/main/java/top/whgojp/modules/ssti/controller/SSTIController.java b/src/main/java/top/whgojp/modules/ssti/controller/SSTIController.java
index 4acbd30..702b8b5 100644
--- a/src/main/java/top/whgojp/modules/ssti/controller/SSTIController.java
+++ b/src/main/java/top/whgojp/modules/ssti/controller/SSTIController.java
@@ -5,18 +5,12 @@
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.expression.EvaluationContext;
-import org.springframework.expression.Expression;
-import org.springframework.expression.ExpressionParser;
-import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.SimpleEvaluationContext;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
-import top.whgojp.common.utils.R;
import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -46,11 +40,12 @@ public String vul1(@ApiParam(name = "para", value = "用户输入参数", requir
// return "vul/ssti/vul"; // 将参数 para 传递到模板 "vul/ssti/template"
// 用户输入直接拼接到模板路径,可能导致SSTI(服务器端模板注入)漏洞
- return "/vul/ssti/" + para;
+ return "vul/ssti/" + para;
}
@GetMapping("/vul2/{path}")
- public void vul2(@PathVariable String path) {
- log.info("SSTI注入:"+path);
+ public String vul2(@PathVariable String path) {
+ log.info("SSTI注入:" + path);
+ return "vul/ssti/" + path;
}
@GetMapping("/vul3")
public String vul3(@ApiParam(name = "para", value = "用户输入参数", required = true) @RequestParam String para, Model model) {
@@ -62,16 +57,18 @@ public String vul3(@ApiParam(name = "para", value = "用户输入参数", requir
public String safe1(@ApiParam(name = "para", value = "用户输入参数", required = true) @RequestParam String para, Model model) {
List white_list = new ArrayList<>(Arrays.asList("vul", "ssti"));
if (white_list.contains(para)){
- return "vul/ssti" + para;
+ return "vul/ssti/" + para;
} else{
return "common/401";
}
}
@GetMapping("/safe2/{path}")
- public void safe2(@PathVariable String path, HttpServletResponse response) {
- log.info("SSTI注入:"+path);
+ public void safe2(@PathVariable String path, HttpServletResponse response) throws IOException {
+ log.info("SSTI注入:" + path);
+ response.setContentType("text/plain;charset=UTF-8");
+ response.getWriter().write("已跳过视图解析,输入路径:" + path);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/top/whgojp/modules/xss/config/XssWebSocketConfig.java b/src/main/java/top/whgojp/modules/xss/config/XssWebSocketConfig.java
new file mode 100644
index 0000000..e1e67f6
--- /dev/null
+++ b/src/main/java/top/whgojp/modules/xss/config/XssWebSocketConfig.java
@@ -0,0 +1,18 @@
+package top.whgojp.modules.xss.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.lang.NonNull;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+
+@Configuration
+@EnableWebSocket
+public class XssWebSocketConfig implements WebSocketConfigurer {
+
+ @Override
+ public void registerWebSocketHandlers(@NonNull WebSocketHandlerRegistry registry) {
+ registry.addHandler(new XssWebSocketHandler(), "/xss/websocket")
+ .setAllowedOrigins("*"); // 故意允许所有源,用于演示XSS风险
+ }
+}
diff --git a/src/main/java/top/whgojp/modules/xss/config/XssWebSocketHandler.java b/src/main/java/top/whgojp/modules/xss/config/XssWebSocketHandler.java
new file mode 100644
index 0000000..18488ef
--- /dev/null
+++ b/src/main/java/top/whgojp/modules/xss/config/XssWebSocketHandler.java
@@ -0,0 +1,53 @@
+package top.whgojp.modules.xss.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.lang.NonNull;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+
+import java.io.IOException;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+@Slf4j
+public class XssWebSocketHandler extends TextWebSocketHandler {
+
+ private static final CopyOnWriteArraySet sessions = new CopyOnWriteArraySet<>();
+
+ @Override
+ public void afterConnectionEstablished(@NonNull WebSocketSession session) {
+ sessions.add(session);
+ log.info("WebSocket connection established - Current connections: {}", sessions.size());
+ try {
+ session.sendMessage(new TextMessage("Connected successfully"));
+ } catch (IOException e) {
+ log.error("Failed to send welcome message: {}", e.getMessage());
+ }
+ }
+
+ @Override
+ protected void handleTextMessage(@NonNull WebSocketSession session, @NonNull TextMessage message) {
+ log.info("Received message: {}", message.getPayload());
+ // 故意不过滤消息内容,用于演示XSS风险
+ broadcast(message);
+ }
+
+ @Override
+ public void afterConnectionClosed(@NonNull WebSocketSession session, @NonNull CloseStatus status) {
+ sessions.remove(session);
+ log.info("WebSocket connection closed - Current connections: {}", sessions.size());
+ }
+
+ private void broadcast(TextMessage message) {
+ for (WebSocketSession session : sessions) {
+ try {
+ if (session.isOpen()) {
+ session.sendMessage(message);
+ }
+ } catch (IOException e) {
+ log.error("Failed to send message to session {}: {}", session.getId(), e.getMessage());
+ }
+ }
+ }
+}
diff --git a/src/main/java/top/whgojp/modules/xss/controller/ActionEnterRewrite.java b/src/main/java/top/whgojp/modules/xss/controller/ActionEnterRewrite.java
index cae747e..6c197b6 100644
--- a/src/main/java/top/whgojp/modules/xss/controller/ActionEnterRewrite.java
+++ b/src/main/java/top/whgojp/modules/xss/controller/ActionEnterRewrite.java
@@ -14,10 +14,6 @@
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
-/**
- * 描述:
- * 创建人: 慌途L
- */
@Slf4j
public class ActionEnterRewrite {
private HttpServletRequest request;
diff --git a/src/main/java/top/whgojp/modules/xss/controller/DomController.java b/src/main/java/top/whgojp/modules/xss/controller/DomController.java
index d745015..e5034c8 100644
--- a/src/main/java/top/whgojp/modules/xss/controller/DomController.java
+++ b/src/main/java/top/whgojp/modules/xss/controller/DomController.java
@@ -14,7 +14,7 @@
* @Date: 2024/5/23 17:25
*/
@Slf4j
-@Api(value = "ReflectController", tags = "跨站脚本-Dom型XSS")
+@Api(value = "DomController", tags = "跨站脚本-DOM型XSS")
@Controller
@CrossOrigin(origins = "*")
@RequestMapping("/xss/dom")
diff --git a/src/main/java/top/whgojp/modules/xss/controller/FileUtils.java b/src/main/java/top/whgojp/modules/xss/controller/FileUtils.java
index d5ab2ec..9a63996 100644
--- a/src/main/java/top/whgojp/modules/xss/controller/FileUtils.java
+++ b/src/main/java/top/whgojp/modules/xss/controller/FileUtils.java
@@ -11,48 +11,47 @@
import java.io.File;
import java.io.IOException;
-import java.util.Random;
+import java.util.UUID;
+
-/**
- * 功能 : 上传文件工具类
- * 创建人 : 慌途L
- */
@Slf4j
public class FileUtils {
public static String upLoadFile(MultipartFile file, String path) {
-
- if(file.isEmpty()){
+ if (file == null || file.isEmpty()) {
log.info("文件为空!");
return null;
}
+
String fileName = file.getOriginalFilename();
- int size = (int) file.getSize();
- log.info(fileName + "-->" + size);
-
- // 取得文件的后缀名。
- String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toUpperCase();
-
- String newFileName =
- System.currentTimeMillis() / 1000 + new Random().nextInt(100000)+"." + ext;
+ log.info("上传文件: {} - 大小: {}", fileName, file.getSize());
- //String path = "F:/test" ;
- File dest = new File(path + "/" + newFileName);
- if(!dest.getParentFile().exists()){ //判断文件父目录是否存在
- dest.getParentFile().mkdir();
+ String ext = getFileExtension(fileName);
+ String newFileName = generateUniqueFileName(ext);
+
+ return saveFile(file, path, newFileName);
+ }
+
+ private static String getFileExtension(String fileName) {
+ return fileName.substring(fileName.lastIndexOf(".") + 1).toUpperCase();
+ }
+
+ private static String generateUniqueFileName(String ext) {
+ return UUID.randomUUID().toString() + "." + ext;
+ }
+
+ private static String saveFile(MultipartFile file, String path, String newFileName) {
+ File dest = new File(path, newFileName);
+ if (!dest.getParentFile().exists()) {
+ dest.getParentFile().mkdirs();
}
+
try {
- file.transferTo(dest); //保存文件
+ file.transferTo(dest);
return newFileName;
- } catch (IllegalStateException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return null;
} catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ log.error("文件保存失败", e);
return null;
}
}
}
-
diff --git a/src/main/java/top/whgojp/modules/xss/controller/JsonpController.java b/src/main/java/top/whgojp/modules/xss/controller/JsonpController.java
new file mode 100644
index 0000000..3c4a30f
--- /dev/null
+++ b/src/main/java/top/whgojp/modules/xss/controller/JsonpController.java
@@ -0,0 +1,17 @@
+package top.whgojp.modules.xss.controller;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/xss")
+public class JsonpController {
+
+ @GetMapping("/jsonp")
+ public String handleJsonp(@RequestParam String callback) {
+ // 故意不验证callback参数,直接拼接返回
+ return callback + "(" + "{\"message\": \"Hello from JSONP\"}" + ");";
+ }
+}
diff --git a/src/main/java/top/whgojp/modules/xss/controller/OtherController.java b/src/main/java/top/whgojp/modules/xss/controller/OtherController.java
index ffc2778..e79a44b 100644
--- a/src/main/java/top/whgojp/modules/xss/controller/OtherController.java
+++ b/src/main/java/top/whgojp/modules/xss/controller/OtherController.java
@@ -84,7 +84,7 @@ public R hackCookie(@RequestParam String cookie, HttpServletRequest request) {
private UploadUtil uploadUtil;
// 文件上传接口
- @ApiOperation(value = "漏洞场景:文件上传导致存储XSS", notes = "原生漏洞场景,未加任何过滤,Controller接口返回Json类型结果")
+ @ApiOperation(value = "漏洞场景:文件上传导致存储XSS", notes = "上传可被浏览器或预览服务解析的文件,后续访问文件时可能触发XSS")
@RequestMapping("/vul1Upload")
@ResponseBody
@SneakyThrows
@@ -110,6 +110,7 @@ public R vul1Upload(@RequestParam("file") MultipartFile file,
} catch (Exception e) {
return R.error("上传错误,请检查后重新上传:" + e.getMessage());
}
+ // XML解析成功后继续落盘,便于演示“解析 + 可访问文件”组合场景。
case "html":
case "svg":
case "pdf":
@@ -122,14 +123,14 @@ public R vul1Upload(@RequestParam("file") MultipartFile file,
return R.error(res);
}
}
- @ApiOperation(value = "漏洞场景:模版引擎解析导致存储XSS", notes = "")
+ @ApiOperation(value = "漏洞场景:模板引擎不安全渲染导致XSS", notes = "th:utext会把内容作为HTML渲染,th:text会进行转义")
@GetMapping("/vul2OtherTemplate")
- public String vul2OtherTemplate(@RequestParam("content") String content,
+ public String vul2OtherTemplate(@RequestParam("payload") String payload,
@RequestParam("type") String type, Model model) {
if ("html".equals(type)) {
- model.addAttribute("html", content);
+ model.addAttribute("html", payload);
} else if ("text".equals(type)) {
- model.addAttribute("text", content);
+ model.addAttribute("text", payload);
}
return "vul/xss/other";
}
diff --git a/src/main/java/top/whgojp/modules/xss/controller/PostMessageController.java b/src/main/java/top/whgojp/modules/xss/controller/PostMessageController.java
new file mode 100644
index 0000000..e5d8e82
--- /dev/null
+++ b/src/main/java/top/whgojp/modules/xss/controller/PostMessageController.java
@@ -0,0 +1,20 @@
+package top.whgojp.modules.xss.controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Controller
+@RequestMapping("/xss/postmessage")
+public class PostMessageController {
+
+ @GetMapping("/sender")
+ public String sender() {
+ return "vul/xss/postmessage/sender";
+ }
+
+ @GetMapping("/receiver")
+ public String receiver() {
+ return "vul/xss/postmessage/receiver";
+ }
+}
diff --git a/src/main/java/top/whgojp/modules/xss/controller/ReflectController.java b/src/main/java/top/whgojp/modules/xss/controller/ReflectController.java
index 2e0b7de..6266dd4 100644
--- a/src/main/java/top/whgojp/modules/xss/controller/ReflectController.java
+++ b/src/main/java/top/whgojp/modules/xss/controller/ReflectController.java
@@ -12,11 +12,11 @@
import org.thymeleaf.util.StringUtils;
import top.whgojp.common.utils.CheckUserInput;
import top.whgojp.common.utils.R;
+import top.whgojp.modules.xss.controller.base.XssBaseController;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -27,65 +27,57 @@
* @Date: 2024/5/20 16:55
*/
@Slf4j
-@Api(value = "ReflectController", tags = "跨站脚本-反射型XSS")
+@Api(value = "ReflectController", tags = "跨站脚本 - 反射型XSS")
@Controller
@CrossOrigin(origins = "*")
@RequestMapping("/xss/reflect")
-public class ReflectController {
+public class ReflectController extends XssBaseController {
+
@Autowired
private CheckUserInput checkUserInput;
- @RequestMapping("")
- public String xssReflect() {
- return "vul/xss/reflect";
- }
- @RequestMapping("/vul")
- public String xssReflectVul() {
- return "vul/xss/reflect-vul";
- }
- @RequestMapping("/safe")
- public String xssReflectSafe() {
- return "vul/xss/reflect-safe";
- }
+ @RequestMapping("/{view}")
+ public String reflect(@PathVariable String view) {
+ return isValidView(view) ? "vul/xss/reflect/" + view : "error/404";
+ }
- @ApiOperation(value = "漏洞场景:GET型与POST型", notes = "原生漏洞场景,未加任何过滤,Controller接口返回Json类型结果")
+ @ApiOperation(value = "漏洞场景:GET型与POST型", notes = "原生漏洞场景,未加任何过滤,Controller接口返回JSON类型结果。JSON本身通常不会直接触发XSS,但前端不安全渲染JSON字段时可能触发")
@RequestMapping("/vul1")
@ResponseBody
- @ApiImplicitParam(name = "content", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
- public R vul1(@ApiParam(name = "content", value = "请求参数", required = true) @RequestParam String content) {
- log.info("反射型XSS:" + content);
- return R.ok(content);
+ @ApiImplicitParam(name = "payload", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
+ public R vul1(@ApiParam(name = "payload", value = "请求参数", required = true) @RequestParam String payload) {
+ return handleXssPayload(payload, "反射型-GET/POST型", false);
}
@ApiOperation(value = "漏洞场景:String", notes = "原生漏洞场景,未加任何过滤,Controller接口返回String")
@GetMapping("/vul2")
@ResponseBody
- @ApiImplicitParam(name = "content", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
- public String vul2(@ApiParam(name = "content", value = "请求参数", required = true) @RequestParam String content) {
-
- return content;
+ @ApiImplicitParam(name = "payload", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
+ public String vul2(@ApiParam(name = "payload", value = "请求参数", required = true) @RequestParam String payload) {
+ log.info("[+]XSS-反射型-String型:" + payload);
+ return payload;
}
@SneakyThrows
- @ApiOperation(value = "漏洞场景:Content-Type问题", notes = "Tomcat内置HttpServletResponse,Content-Type导致反射XSS")
+ @ApiOperation(value = "漏洞场景:Content-Type问题", notes = "响应Content-Type决定浏览器解析方式,不可信内容以text/html返回时可能导致反射XSS")
@GetMapping("/vul3")
@ResponseBody
@ApiImplicitParams({
@ApiImplicitParam(name = "type", value = "类型", dataType = "String", paramType = "query", dataTypeClass = String.class),
- @ApiImplicitParam(name = "content", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
+ @ApiImplicitParam(name = "payload", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
})
- public void vul3(@ApiParam(name = "type", value = "类型", required = true) @RequestParam String type, @ApiParam(name = "content", value = "请求参数", required = true) @RequestParam String content, HttpServletResponse response) {
+ public void vul3(@ApiParam(name = "type", value = "类型", required = true) @RequestParam String type, @ApiParam(name = "payload", value = "请求参数", required = true) @RequestParam String payload, HttpServletResponse response) {
switch (type) {
case "html":
- response.getWriter().print(content);
- log.info("反射型XSS,Content-Type:text/html;charset=utf-8:" + content);
+ response.getWriter().print(payload);
+ log.info("[+]XSS-反射性-Content-Type:text/html;charset=utf-8:" + payload);
response.setContentType("text/html;charset=utf-8");
response.getWriter().flush();
break;
case "plain":
- log.info("反射型XSS,Content-Type:text/plain;charset=utf-8:" + content);
- response.getWriter().print(content);
- response.setContentType("text/plain;charset=utf-8"); // response默认返回Content-Type类型是text/plain
+ log.info("[+]XSS-反射性-Content-Type:text/plain;charset=utf-8:" + payload);
+ response.getWriter().print(payload);
+ response.setContentType("text/plain;charset=utf-8");
response.getWriter().flush();
break;
default:
@@ -95,44 +87,51 @@ public void vul3(@ApiParam(name = "type", value = "类型", required = true) @Re
break;
}
}
+
private static final String WHITELIST_REGEX = "^[a-zA-Z0-9_\\s]+$";
private static final Pattern pattern = Pattern.compile(WHITELIST_REGEX);
- @ApiOperation(value = "安全代码:用户输入验证和过滤", notes = "对用户输入的数据进行验证和过滤,确保不包含恶意代码。使用白名单过滤,只允许特定类型的输入,如纯文本或指定格式的数据")
- @RequestMapping("/safe1")
+ @ApiOperation(value = "安全代码:用户输入验证和过滤", notes = "使用白名单限制输入格式,适合约束字段类型;最终仍需根据输出位置进行上下文编码")
+ @GetMapping("/safe1")
@ResponseBody
@ApiImplicitParams({
@ApiImplicitParam(name = "type", value = "类型", dataType = "String", paramType = "query", dataTypeClass = String.class),
@ApiImplicitParam(name = "content", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
})
- public R safe1(@ApiParam(name = "type", value = "类型", required = true) @RequestParam String type, @ApiParam(name = "content", value = "请求参数", required = true) @RequestParam String content) {
+ public R safe1(@ApiParam(name = "type", value = "类型", required = true) @RequestParam String type, @ApiParam(name = "payload", value = "请求参数", required = true) @RequestParam String payload) {
String filterContented = "";
switch (type) {
case "frontEnd":
- filterContented = content; // 前端过滤后传递过来 后端未进行处理(同样存在安全问题)
+ log.info("[-]XSS-反射性-前端白名单过滤:" + payload);
+ filterContented = payload; // 前端过滤后传递过来 后端未进行处理(同样存在安全问题)
break;
case "backEnd":
- Matcher matcher = pattern.matcher(content);
- if (matcher.matches()){
- return R.ok(content);
- }else return R.error("输入内容包含非法字符,请检查输入");
+ log.info("[-]XSS-反射性-后端白名单过滤:" + payload);
+ Matcher matcher = pattern.matcher(payload);
+ if (matcher.matches()) {
+ return R.ok(payload);
+ } else return R.error("输入内容包含非法字符,请检查输入");
}
return R.ok(filterContented);
}
- @ApiOperation(value = "安全代码:内容安全策略-CSP防护", notes = "内容安全策略(Content Security Policy)是一种由浏览器实施的安全机制,旨在减少和防范跨站脚本攻击(XSS)等安全威胁。它通过允许网站管理员定义哪些内容来源是可信任的,从而防止恶意内容的加载和执行")
- @RequestMapping("/safe2")
+
+ @ApiOperation(value = "安全代码:内容安全策略-CSP防护", notes = "内容安全策略(Content Security Policy)是由浏览器实施的额外防护层,可降低恶意脚本加载和执行风险,但不能替代输出编码与安全模板/DOM用法")
+ @GetMapping("/safe2")
@ResponseBody
- @ApiImplicitParam(name = "content", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
- public String safe2(@ApiParam(name = "content", value = "请求参数", required = true) @RequestParam String content,HttpServletResponse response) {
- response.setHeader("Content-Security-Policy","default-src self");
- response.setHeader("Content-Security-Policy-Report-Only", "default-src 'self'; other-uri /xss/reflect/csp-other-endpoint");
- return content;
+ @ApiImplicitParam(name = "payload", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
+ public String safe2(@ApiParam(name = "payload", value = "请求参数", required = true) @RequestParam String payload, HttpServletResponse response) {
+ response.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self'");
+ response.setHeader("Content-Security-Policy-Report-Only", "default-src 'self'; report-uri /xss/reflect/csp-report-endpoint");
+ log.info("[-]XSS-反射性-内容安全策略-CSP防护:" + payload);
+ return payload;
}
+
@GetMapping("/a-safe2-CSP-front")
- public String safeCSPFront(){
+ public String safeCSPFront() {
return "vul/xss/csp-protect";
}
+
@PostMapping("/csp-report-endpoint")
public void receiveCSPReport(@RequestBody String reportData) {
// 获取当前时间
@@ -152,27 +151,30 @@ public void receiveCSPReport(@RequestBody String reportData) {
// System.err.println("Error writing CSP violation other to file: " + e.getMessage());
// }
}
- @ApiOperation(value = "安全代码:特殊字符实体转义", notes = "特殊字符实体转义是一种将 HTML 中的特殊字符转换为预定义实体表示的过程。这种转义是为了确保在 HTML 页面中正确显示特定字符,同时避免它们被浏览器误解为 HTML 标签或JavaScript代码的一部分,从而导致页面结构混乱或安全漏洞。")
- @RequestMapping("/safe3")
+
+ @ApiOperation(value = "安全代码:HTML正文输出编码", notes = "将HTML正文文本中的特殊字符编码为实体,避免浏览器把不可信数据解析为HTML标签或JavaScript。不同输出上下文需要使用不同编码策略")
+ @GetMapping("/safe3")
@ResponseBody
@ApiImplicitParams({
@ApiImplicitParam(name = "type", value = "类型", dataType = "String", paramType = "query", dataTypeClass = String.class),
- @ApiImplicitParam(name = "content", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
+ @ApiImplicitParam(name = "payload", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
})
- public R safe3(@ApiParam(name = "type", value = "类型", required = true) @RequestParam String type, @ApiParam(name = "content", value = "请求参数", required = true) @RequestParam String content) {
+ public R safe3(@ApiParam(name = "type", value = "类型", required = true) @RequestParam String type, @ApiParam(name = "payload", value = "请求参数", required = true) @RequestParam String payload) {
String filterContented = "";
- switch (type){
+ switch (type) {
case "manual":
- content = StringUtils.replace(content, "&", "&");
- content = StringUtils.replace(content, "<", "<");
- content = StringUtils.replace(content, ">", ">");
- content = StringUtils.replace(content, "\"", """);
- content = StringUtils.replace(content, "'", "'");
- content = StringUtils.replace(content, "/", "/");
- filterContented = content;
+ payload = StringUtils.replace(payload, "&", "&");
+ payload = StringUtils.replace(payload, "<", "<");
+ payload = StringUtils.replace(payload, ">", ">");
+ payload = StringUtils.replace(payload, "\"", """);
+ payload = StringUtils.replace(payload, "'", "'");
+ payload = StringUtils.replace(payload, "/", "/");
+ filterContented = payload;
+ log.info("[-]XSS-反射型-HTML正文输出编码-手动编码:" + payload);
break;
case "spring":
- filterContented = HtmlUtils.htmlEscape(content);
+ filterContented = HtmlUtils.htmlEscape(payload);
+ log.info("[-]XSS-反射型-HTML正文输出编码-Spring框架:" + payload);
break;
default:
return R.error("参数输入有误!");
@@ -180,11 +182,11 @@ public R safe3(@ApiParam(name = "type", value = "类型", required = true) @Requ
return R.ok(filterContented);
}
- @ApiOperation(value = "安全代码:HttpOnly配置", notes = "HttpOnly是HTTP响应头属性,用于增强Web应用程序安全性。它防止客户端脚本访问(只能通过http/https协议访问)带有HttpOnly标记的 cookie,从而减少跨站点脚本攻击(XSS)的风险。")
+ @ApiOperation(value = "安全代码:HttpOnly配置", notes = "HttpOnly可以阻止客户端脚本直接读取带有该属性的Cookie,降低XSS窃取Cookie的影响,但不能修复XSS本身")
@RequestMapping(value = "/safe4", method = RequestMethod.GET)
@ResponseBody
- @ApiImplicitParam(name = "content", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
- public R safe4(@ApiParam(name = "content", value = "请求参数", required = true) String content, HttpServletRequest request,HttpServletResponse response) {
+ @ApiImplicitParam(name = "payload", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
+ public R safe4(@ApiParam(name = "payload", value = "请求参数", required = true) String payload, HttpServletRequest request, HttpServletResponse response) {
Cookie cookie = request.getCookies()[0];
cookie.setHttpOnly(true); // 设置为 HttpOnly
@@ -192,6 +194,6 @@ public R safe4(@ApiParam(name = "content", value = "请求参数", required = tr
cookie.setPath("/");
response.addCookie(cookie);
- return R.ok("已设置httponly(有效期10分钟),请打开控制台查看cookie属性:"+content);
+ return R.ok("已设置httponly(有效期10分钟),请打开控制台查看cookie属性:" + payload);
}
}
diff --git a/src/main/java/top/whgojp/modules/xss/controller/StoreController.java b/src/main/java/top/whgojp/modules/xss/controller/StoreController.java
index a91f126..1ddb25d 100644
--- a/src/main/java/top/whgojp/modules/xss/controller/StoreController.java
+++ b/src/main/java/top/whgojp/modules/xss/controller/StoreController.java
@@ -45,14 +45,14 @@ public String xssStore() {
return "vul/xss/store";
}
- @ApiOperation(value = "漏洞场景:原生无过滤", notes = "原生漏洞场景,未加任何过滤,将用户输入存储到数据库中")
- @RequestMapping("/vul")
+ @ApiOperation(value = "漏洞场景:原生无过滤", notes = "原生漏洞场景,未加任何过滤,将用户输入和User-Agent持久化;后续页面不安全渲染时触发存储型XSS")
+ @PostMapping("/vul")
@ResponseBody
- @ApiImplicitParam(name = "content", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
- public R vul(@ApiParam(name = "content", value = "请求参数", required = true) @RequestParam String content,HttpServletRequest request) {
- log.info("存储型XSS:" + content);
+ @ApiImplicitParam(name = "payload", value = "请求参数", dataType = "String", paramType = "query", dataTypeClass = String.class)
+ public R vul(@ApiParam(name = "payload", value = "请求参数", required = true) @RequestParam String payload,HttpServletRequest request) {
+ log.info("[+]XSS-存储性-原生无过滤:" + payload);
String ua = request.getHeader("User-Agent");
- final int code = xssService.insertOne(content,ua);
+ final int code = xssService.insertOne(payload,ua);
if (code == 1) {
log.info("插入数据成功!");
return R.ok("插入数据成功!");
diff --git a/src/main/java/top/whgojp/modules/xss/controller/UEditorController.java b/src/main/java/top/whgojp/modules/xss/controller/UEditorController.java
index 0c4546a..8d9b938 100644
--- a/src/main/java/top/whgojp/modules/xss/controller/UEditorController.java
+++ b/src/main/java/top/whgojp/modules/xss/controller/UEditorController.java
@@ -46,14 +46,8 @@ public String ueditor() {
public void getConfigInfo(HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/json");
- String rootPath = "";
- // 判断当前系统是否是Windows系统
- if (isWindowsSystem()) {
- rootPath = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "static/ueditor/jsp";
- } else {
- // 将config.json文件放在jar包同级目录下
- rootPath = "/Users/whgojp/Desktop/Security/JAVA/JavaSecLab/src/main/resources/static/lib/ueditor/jsp";
- }
+ String rootPath = Objects.requireNonNull(ClassUtils.getDefaultClassLoader().getResource("")).getPath()
+ + "static/lib/ueditor/jsp";
log.info("rootPath:{}", rootPath);
try {
response.setCharacterEncoding("UTF-8");
diff --git a/src/main/java/top/whgojp/modules/xss/controller/base/XssBaseController.java b/src/main/java/top/whgojp/modules/xss/controller/base/XssBaseController.java
new file mode 100644
index 0000000..4ad2018
--- /dev/null
+++ b/src/main/java/top/whgojp/modules/xss/controller/base/XssBaseController.java
@@ -0,0 +1,41 @@
+package top.whgojp.modules.xss.controller.base;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.thymeleaf.util.StringUtils;
+import top.whgojp.common.utils.CheckUserInput;
+import top.whgojp.common.utils.R;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Slf4j
+public abstract class XssBaseController {
+ @Autowired
+ protected CheckUserInput checkUserInput;
+
+ protected R handleXssPayload(String payload, String type, boolean enableFilter) {
+ if (StringUtils.isEmpty(payload)) {
+ return R.error("参数不能为空");
+ }
+
+ log.info("[+]XSS-{}-收到payload:{}", type, payload);
+
+ if (enableFilter) {
+ String filteredPayload = checkUserInput.filter(payload);
+ log.info("[+]XSS-{}-过滤后:{}", type, filteredPayload);
+ return R.ok(filteredPayload);
+ }
+
+ return R.ok(payload);
+ }
+
+ protected String getUserAgent(HttpServletRequest request) {
+ String ua = request.getHeader("User-Agent");
+ return StringUtils.isEmpty(ua) ? "unknown" : ua;
+ }
+
+ protected boolean isValidView(String view) {
+ return !StringUtils.isEmpty(view) &&
+ (view.equals("vul") || view.equals("safe"));
+ }
+}
diff --git a/src/main/java/top/whgojp/modules/xss/service/impl/XssServiceImpl.java b/src/main/java/top/whgojp/modules/xss/service/impl/XssServiceImpl.java
index 034a024..164e309 100644
--- a/src/main/java/top/whgojp/modules/xss/service/impl/XssServiceImpl.java
+++ b/src/main/java/top/whgojp/modules/xss/service/impl/XssServiceImpl.java
@@ -8,7 +8,6 @@
import top.whgojp.modules.xss.service.XssService;
import top.whgojp.modules.xss.mapper.XssMapper;
import org.springframework.stereotype.Service;
-
import java.util.List;
/**
@@ -18,30 +17,42 @@
*/
@Slf4j
@Service
-public class XssServiceImpl extends ServiceImpl
- implements XssService{
+public class XssServiceImpl extends ServiceImpl implements XssService {
@Autowired
private XssMapper xssMapper;
@Override
public int insertOne(String content, String ua) {
- final int code = xssMapper.insertAll(content,ua,DateUtil.now());
- return code;
+ try {
+ log.info("插入XSS记录 - content: {}, ua: {}", content, ua);
+ final int code = xssMapper.insertAll(content,ua,DateUtil.now());
+ return code;
+ } catch (Exception e) {
+ log.error("插入XSS记录失败", e);
+ return 0;
+ }
}
@Override
public List selectAll() {
- List xssList = xssMapper.selectAll();
- return xssList;
+ try {
+ List xssList = xssMapper.selectAll();
+ return xssList;
+ } catch (Exception e) {
+ log.error("查询XSS记录失败", e);
+ return null;
+ }
}
@Override
public int deleteById(int id) {
- int i = xssMapper.deleteById(id);
- return i;
+ try {
+ log.info("删除XSS记录 - id: {}", id);
+ int i = xssMapper.deleteById(id);
+ return i;
+ } catch (Exception e) {
+ log.error("删除XSS记录失败 - id: {}", id, e);
+ return 0;
+ }
}
}
-
-
-
-
diff --git a/src/main/java/top/whgojp/modules/xxe/controller/XXEController.java b/src/main/java/top/whgojp/modules/xxe/controller/XXEController.java
index 8c175bd..7f546b9 100644
--- a/src/main/java/top/whgojp/modules/xxe/controller/XXEController.java
+++ b/src/main/java/top/whgojp/modules/xxe/controller/XXEController.java
@@ -17,6 +17,7 @@
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
+import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParser;
@@ -73,7 +74,7 @@ public void characters(char[] ch, int start, int length) {
/**
- * javax.xml.parsers.SAXParser 是 XMLReader 的替代品,它提供了更多的安全措施,例如默认禁用 DTD 和外部实体的声明,如果需要使用 DTD 或外部实体,可以手动启用它们,并使用相应的安全措施
+ * SAXParser 解析不可信 XML 时同样需要显式关闭 DTD、外部实体和外部 DTD 加载。
*/
@RequestMapping(value = "/vul2")
@ResponseBody
@@ -100,6 +101,19 @@ public void characters(char[] ch, int start, int length) {
}
}
+ @RequestMapping(value = "/vul3")
+ @ResponseBody
+ public String vul3(@RequestParam String payload) {
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.parse(new InputSource(new StringReader(payload)));
+ return formatXmlText(document.getDocumentElement().getTextContent());
+ } catch (Exception e) {
+ return e.toString();
+ }
+ }
+
// @ApiOperation(value = "vul:xmlbeam")
// @RequestMapping(value = "/xmlbeam")
@@ -215,6 +229,8 @@ public String safe1(@RequestParam String payload) {
xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ xmlReader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ xmlReader.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader("")));
StringWriter stringWriter = new StringWriter();
xmlReader.setContentHandler(new DefaultHandler() {
public void characters(char[] ch, int start, int length) {
@@ -234,6 +250,29 @@ public void characters(char[] ch, int start, int length) {
}
}
+ @RequestMapping(value = "/safe3")
+ @ResponseBody
+ public String safe3(@RequestParam String payload) {
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ factory.setXIncludeAware(false);
+ factory.setExpandEntityReferences(false);
+ setAttributeIfSupported(factory, XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ setAttributeIfSupported(factory, XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ builder.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader("")));
+ Document document = builder.parse(new InputSource(new StringReader(payload)));
+ return formatXmlText(document.getDocumentElement().getTextContent());
+ } catch (Exception e) {
+ return e.toString();
+ }
+ }
+
@RequestMapping(value = "/safe2")
@ResponseBody
public String safe2(@RequestParam String payload) {
@@ -246,6 +285,20 @@ public String safe2(@RequestParam String payload) {
return "[-]XML内容安全";
}
+ private String formatXmlText(String text) {
+ if (text == null) {
+ return "";
+ }
+ return text.replace("\n", " ");
+ }
+
+ private void setAttributeIfSupported(DocumentBuilderFactory factory, String name, String value) {
+ try {
+ factory.setAttribute(name, value);
+ } catch (IllegalArgumentException e) {
+ log.warn("XML parser does not support attribute: {}", name);
+ }
+ }
}
diff --git a/src/main/java/top/whgojp/security/SecurityConfigurer.java b/src/main/java/top/whgojp/security/SecurityConfigurer.java
index 403ed45..51ee6aa 100755
--- a/src/main/java/top/whgojp/security/SecurityConfigurer.java
+++ b/src/main/java/top/whgojp/security/SecurityConfigurer.java
@@ -3,6 +3,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@@ -19,7 +20,6 @@
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import top.whgojp.common.config.AuthIgnoreConfig;
import top.whgojp.common.constant.SysConstant;
import top.whgojp.common.filter.ValidateCodeFilter;
@@ -81,7 +81,16 @@ protected void configure(HttpSecurity http) throws Exception {
permitAll.add("/static/js/**");
permitAll.add("/static/css/**");
permitAll.add("/static/other/**");
-// permitAll.add("/druid/**");
+ permitAll.add("/images/**");
+ permitAll.add("/lib/**");
+ permitAll.add("/js/**");
+ permitAll.add("/css/**");
+ permitAll.add("/api/**");
+ permitAll.add("/upload/**");
+ permitAll.add("/other/**");
+ permitAll.add("/ssrf/internal/**");
+ permitAll.add("/ssrf/redirect");
+ permitAll.add("/druid/**");
// permitAll.add("/ueditor/**");
String[] urls = permitAll.stream().distinct().toArray(String[]::new);
@@ -92,7 +101,8 @@ protected void configure(HttpSecurity http) throws Exception {
// 权限
http.authorizeRequests(authorize ->
// 开放权限
- authorize.antMatchers(urls).permitAll()
+ authorize.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
+ .antMatchers(urls).permitAll()
.anyRequest().authenticated());
// 使用jwt 关闭session校验
@@ -100,8 +110,8 @@ protected void configure(HttpSecurity http) throws Exception {
// http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
- // 如果不需要验证码校验登录 可以注释掉该行
-// http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
+ // 登录验证码校验,验证码一次性使用,避免同一验证码被重复提交。
+ http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
// 添加session管理器 session失效后跳到登录页
@@ -116,8 +126,9 @@ protected void configure(HttpSecurity http) throws Exception {
.successHandler(authenticationSuccessHandler())
.failureHandler(customSimpleUrlAuthenticationFailureHandler());
-
- http.exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.BAD_REQUEST));
+ // TODO: 2025/1/12 解决登录就报错400状态码问题 GPT害死人啊 注释后就没问题了
+ // 设置自定义的未认证用户访问受保护资源时的响应行为,并在用户未通过认证时返回 HTTP 状态码 400 BAD_REQUEST
+// http.exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.BAD_REQUEST));
http.logout()
.logoutSuccessHandler(customLogoutSuccessHandler())
@@ -132,15 +143,37 @@ protected void configure(HttpSecurity http) throws Exception {
}
- // 解决跨域
+ // 全局跨域演示配置。跨源安全模块需要由 Controller 自己控制响应头,避免被全局通配配置污染。
public CorsConfigurationSource corsConfigurationSource() {
- UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
- CorsConfiguration corsConfiguration = new CorsConfiguration();
- corsConfiguration.addAllowedOrigin("*");
- corsConfiguration.addAllowedHeader("*");
- corsConfiguration.addAllowedMethod("*");
- source.registerCorsConfiguration("/**", corsConfiguration);
- return source;
+ return request -> {
+ String uri = request.getRequestURI();
+ if (uri.startsWith("/crossorigin/corsVul")) {
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.addAllowedOriginPattern("*");
+ corsConfiguration.setAllowCredentials(true);
+ corsConfiguration.addAllowedHeader("*");
+ corsConfiguration.addAllowedMethod("*");
+ return corsConfiguration;
+ }
+ if (uri.startsWith("/crossorigin/corsSafe")) {
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.addAllowedOrigin("http://127.0.0.1:8080");
+ corsConfiguration.addAllowedOrigin("https://127.0.0.1:8080");
+ corsConfiguration.setAllowCredentials(true);
+ corsConfiguration.addAllowedHeader("Content-Type");
+ corsConfiguration.addAllowedMethod("GET");
+ corsConfiguration.addAllowedMethod("OPTIONS");
+ return corsConfiguration;
+ }
+ if (uri.startsWith("/crossorigin/")) {
+ return null;
+ }
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.addAllowedOrigin("*");
+ corsConfiguration.addAllowedHeader("*");
+ corsConfiguration.addAllowedMethod("*");
+ return corsConfiguration;
+ };
}
@Bean
@@ -153,6 +186,7 @@ public PasswordEncoder passwordEncoder() {
public AuthenticationSuccessHandler authenticationSuccessHandler() {
CustomSavedRequestAwareAuthenticationSuccessHandler customSavedRequestAwareAuthenticationSuccessHandler = new CustomSavedRequestAwareAuthenticationSuccessHandler();
customSavedRequestAwareAuthenticationSuccessHandler.setDefaultTargetUrl("/index");
+ customSavedRequestAwareAuthenticationSuccessHandler.setAlwaysUseDefaultTargetUrl(true);
// customSavedRequestAwareAuthenticationSuccessHandler.setEmailPush(emailPush);
// customSavedRequestAwareAuthenticationSuccessHandler.setSmsService(smsService);
// customSavedRequestAwareAuthenticationSuccessHandler.setWeChatService(wechatService);
@@ -182,4 +216,4 @@ public AuthenticationFailureHandler customSimpleUrlAuthenticationFailureHandler(
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/top/whgojp/security/handler/CustomSimpleUrlAuthenticationFailureHandler.java b/src/main/java/top/whgojp/security/handler/CustomSimpleUrlAuthenticationFailureHandler.java
index 0ac6635..ebca529 100755
--- a/src/main/java/top/whgojp/security/handler/CustomSimpleUrlAuthenticationFailureHandler.java
+++ b/src/main/java/top/whgojp/security/handler/CustomSimpleUrlAuthenticationFailureHandler.java
@@ -10,7 +10,6 @@
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
import top.whgojp.common.constant.SysConstant;
import top.whgojp.common.enums.LoginError;
@@ -26,14 +25,10 @@ public class CustomSimpleUrlAuthenticationFailureHandler extends SimpleUrlAuthen
private static final String DEFAULT_FAILURE_URL = SysConstant.LOGIN_URL;
- private String defaultFailureUrl;
-
-
-
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
- super.onAuthenticationFailure(request, response, exception);
setDefaultFailureUrl(determineFailureUrl(exception));
+ super.onAuthenticationFailure(request, response, exception);
log.info("当前异常:"+exception.getMessage());
String loginIp = request.getRemoteHost();
@@ -50,24 +45,22 @@ public void CustomOnAuthenticationFailure(Exception exception){
}
private String determineFailureUrl(AuthenticationException exception) {
- // 默认设置登录错误页面为/login
- defaultFailureUrl = StringUtils.hasLength(defaultFailureUrl) ? defaultFailureUrl : DEFAULT_FAILURE_URL;
-
+ String failureUrl = DEFAULT_FAILURE_URL;
Integer failureType = determineFailureType(exception).getType();
if (failureType != null) {
- defaultFailureUrl += defaultFailureUrl.lastIndexOf("?") > 0 ? "&" : "?" + "error=" + failureType;
+ failureUrl += (failureUrl.lastIndexOf("?") > 0 ? "&" : "?") + "error=" + failureType;
}
- return defaultFailureUrl;
+ return failureUrl;
}
private LoginError determineFailureType(AuthenticationException exception) {
- if (exception.getMessage() == "验证码为空"){
+ if ("验证码为空".equals(exception.getMessage())){
return LoginError.CAPTCHANOTFOUND;
- } else if (exception.getMessage() == "验证码过期") {
+ } else if ("验证码过期".equals(exception.getMessage())) {
return LoginError.CAPTCHAEXPIRED;
- } else if (exception.getMessage() == "验证码不正确") {
+ } else if ("验证码不正确".equals(exception.getMessage())) {
return LoginError.CAPTCHAERROR;
} else if (exception instanceof UsernameNotFoundException) {
return LoginError.USERNAMENOTFOUND;
@@ -82,14 +75,4 @@ private LoginError determineFailureType(AuthenticationException exception) {
return LoginError.FAILURE;
}
-
- public String getDefaultFailureUrl() {
- return defaultFailureUrl;
- }
-
- @Override
- public void setDefaultFailureUrl(String defaultFailureUrl) {
- super.setDefaultFailureUrl(defaultFailureUrl);
- }
-
}
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index 999df61..a0c1ca4 100755
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -1,43 +1,73 @@
spring:
datasource:
- type: com.zaxxer.hikari.HikariDataSource
- driver-class-name: com.mysql.cj.jdbc.Driver
- username: root
- password: QWE123qwe
- url: jdbc:mysql://localhost:13306/JavaSecLab?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
- druid:
- initial-size: 5
- min-idle: 5
- max-active: 20
- max-wait: 60000
- time-between-eviction-runs-millis: 60000
- min-evictable-idle-time-millis: 300000
- validation-query: SELECT 1 FROM DUAL
- test-while-idle: true
- test-on-borrow: false
- test-on-return: false
- pool-prepared-statements: true
- max-pool-prepared-statement-per-connection-size: 20
- filters: stat,log4j # wall 这里关闭sql防火墙
- connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
- remove-abandoned: true
- remove-abandoned-timeout: 1800
- log-abandoned: true
- web-stat-filter:
- enabled: true
- stat-view-servlet:
- enabled: true
- url-pattern: /druid/*
- # login-username: admin
- # login-password: admin
- reset-enable: false
- # 防火墙配置
-# wall:
-# config:
-# multi-statement-allow: false
+ primary:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:13306/JavaSecLab?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
+ username: root
+ password: QWE123qwe
+ druid:
+ initial-size: 5
+ min-idle: 5
+ max-active: 20
+ max-wait: 30000
+ validation-query: SELECT 1 FROM DUAL
+ test-while-idle: true
+ time-between-eviction-runs-millis: 60000
+ min-evictable-idle-time-millis: 300000
+ pool-prepared-statements: true
+ max-pool-prepared-statement-per-connection-size: 20
+ log-abandoned: true
+ remove-abandoned: true
+ secondary:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:13306/JavaSecLab?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
+ username: root
+ password: QWE123qwe
+ druid:
+ initial-size: 5
+ min-idle: 5
+ max-active: 20
+ max-wait: 30000
+ validation-query: SELECT 1 FROM DUAL
+ test-while-idle: true
+ time-between-eviction-runs-millis: 60000
+ min-evictable-idle-time-millis: 300000
+ pool-prepared-statements: true
+ max-pool-prepared-statement-per-connection-size: 20
+ log-abandoned: true
+ remove-abandoned: true
-# Hibernate 配置:将当前上下文策略设置为 Spring
-# jpa:
-# properties:
-# hibernate:
-# current_session_context_class: thread
\ No newline at end of file
+ jpa:
+ database-platform: org.hibernate.dialect.MySQLDialect
+ show-sql: true
+ hibernate:
+ ddl-auto: update
+ properties:
+ hibernate:
+ format_sql: true
+ session_factory_name: sessionFactory
+ session_factory_name_is_jndi: false
+ current_session_context_class: thread
+ transaction:
+ auto_close_session: true
+ connection:
+ provider_disables_autocommit: true
+ generate_statistics: true
+ jdbc:
+ time_zone: UTC
+ session:
+ events:
+ log:
+ LOG_QUERIES_SLOWER_THAN_MS: 0
+ flush_mode: AUTO
+ default_schema: JavaSecLab
+ default_catalog: JavaSecLab
+
+logging:
+ level:
+ root: INFO # 默认日志级别
+ com.alibaba.druid.pool: DEBUG # 启用 Druid 的 DEBUG 日志(排查数据库连接池问题时启用)
+ org.hibernate.SQL: DEBUG # 启用 Hibernate SQL 日志
+ org.hibernate.type.descriptor.sql.BasicBinder: TRACE # 启用 Hibernate 参数绑定日志
\ No newline at end of file
diff --git a/src/main/resources/application-docker.yml b/src/main/resources/application-docker.yml
index c0151f3..f7b4556 100755
--- a/src/main/resources/application-docker.yml
+++ b/src/main/resources/application-docker.yml
@@ -1,45 +1,73 @@
spring:
datasource:
- type: com.zaxxer.hikari.HikariDataSource
- driver-class-name: com.mysql.cj.jdbc.Driver
- username: root
- password: QWE123qwe
- url: jdbc:mysql://Container-MYSQL8:3306/JavaSecLab?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
-# url: jdbc:mysql://47.94.130.42:3306/JavaSecLab?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
- druid:
- initial-size: 5
- min-idle: 5
- max-active: 20
- max-wait: 60000
- time-between-eviction-runs-millis: 60000
- min-evictable-idle-time-millis: 300000
- validation-query: SELECT 1 FROM DUAL
- test-while-idle: true
- test-on-borrow: false
- test-on-return: false
- pool-prepared-statements: true
- max-pool-prepared-statement-per-connection-size: 20
- filters: stat,log4j # wall 这里关闭sql防火墙
- connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
- remove-abandoned: true
- remove-abandoned-timeout: 1800
- log-abandoned: true
- web-stat-filter:
- enabled: true
- stat-view-servlet:
- enabled: true
- url-pattern: /druid/*
- # login-username: admin
- # login-password: admin
- reset-enable: false
- # 防火墙配置
- # wall:
- # config:
- # multi-statement-allow: false
+ primary:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://mysql:3306/JavaSecLab?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
+ username: root
+ password: QWE123qwe
+ druid:
+ initial-size: 5
+ min-idle: 5
+ max-active: 20
+ max-wait: 30000
+ validation-query: SELECT 1 FROM DUAL
+ test-while-idle: true
+ time-between-eviction-runs-millis: 60000
+ min-evictable-idle-time-millis: 300000
+ pool-prepared-statements: true
+ max-pool-prepared-statement-per-connection-size: 20
+ log-abandoned: true
+ remove-abandoned: true
+ secondary:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://mysql:3306/JavaSecLab?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
+ username: root
+ password: QWE123qwe
+ druid:
+ initial-size: 5
+ min-idle: 5
+ max-active: 20
+ max-wait: 30000
+ validation-query: SELECT 1 FROM DUAL
+ test-while-idle: true
+ time-between-eviction-runs-millis: 60000
+ min-evictable-idle-time-millis: 300000
+ pool-prepared-statements: true
+ max-pool-prepared-statement-per-connection-size: 20
+ log-abandoned: true
+ remove-abandoned: true
jpa:
- hibernate:
- ddl-auto: none
- database: mysql
database-platform: org.hibernate.dialect.MySQLDialect
- show-sql: true
\ No newline at end of file
+ show-sql: true
+ hibernate:
+ ddl-auto: update
+ properties:
+ hibernate:
+ format_sql: true
+ session_factory_name: sessionFactory
+ session_factory_name_is_jndi: false
+ current_session_context_class: thread
+ transaction:
+ auto_close_session: true
+ connection:
+ provider_disables_autocommit: true
+ generate_statistics: true
+ jdbc:
+ time_zone: UTC
+ session:
+ events:
+ log:
+ LOG_QUERIES_SLOWER_THAN_MS: 0
+ flush_mode: AUTO
+ default_schema: JavaSecLab
+ default_catalog: JavaSecLab
+
+logging:
+ level:
+ root: INFO # 默认日志级别
+ com.alibaba.druid.pool: DEBUG # 启用 Druid 的 DEBUG 日志(排查数据库连接池问题时启用)
+ org.hibernate.SQL: DEBUG # 启用 Hibernate SQL 日志
+ org.hibernate.type.descriptor.sql.BasicBinder: TRACE # 启用 Hibernate 参数绑定日志
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 2b612c5..facdf93 100755
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -5,6 +5,8 @@ spring:
# 环境 dev|docker
profiles:
active: docker
+ main:
+ allow-bean-definition-overriding: true
thymeleaf:
mode: LEGACYHTML5 #模板类型
cache: false #缓存
@@ -13,10 +15,7 @@ spring:
suffix: .html
mvc:
pathmatch:
- matching-strategy: ant_path_matcher #解决swaggerUI不匹配接口
-# view: # 设置JSP视图的前缀和后缀
-# prefix: /WEB-INF/jsp/
-# suffix: .jsp
+ matching-strategy: ANT_PATH_MATCHER #解决swaggerUI不匹配接口
swagger:
enable: true
@@ -41,6 +40,7 @@ management:
web:
exposure:
include: '*'
+ exclude:
base-path: /sys/actuator
logging:
@@ -49,12 +49,18 @@ logging:
# mybaits-plus配置
mybatis-plus:
configuration:
+ map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# MyBatis Mapper所对应的XML文件位置
- mapper-locations: /mapper/**/*Mapper.xml
+ mapper-locations: classpath*:/mapper/**/*.xml
global-config:
# 关闭MP3.0自带的banner
banner: false
+ db-config:
+ logic-delete-field: deleted
+ logic-delete-value: 1
+ logic-not-delete-value: 0
+ type-aliases-package: top.whgojp.modules.*.entity
folder:
upload: /tmp/upload
@@ -89,4 +95,9 @@ J2FhZOq2OdVaWGKwW9BEcnx1QjMSZgciYR9anFyX4haMlDUdSBQYt0FwfRFfzARd
hGUahXhPvN1OkI+772dFhjpQYxf02oKrdW/pNrTAoYyE9tCUUeZngUZ6SkN+TlJa
ouK1o4xnmMD2YhHhzmxyn8wlLB8KopMzCQ8WaooivlJbyXQVp6bq9UFaeQW0NtIB
tzMFGyiO+DvR4pO52uQLEBU=
------END PRIVATE KEY-----"
\ No newline at end of file
+-----END PRIVATE KEY-----"
+
+jwt:
+ key: f3a4c6d5b9bfeff28b1f529b0840134bcd4183474e2d4a97c05615a134e4f4da
+
+#debug: true
\ No newline at end of file
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
index cf6c02b..79d4bf5 100755
--- a/src/main/resources/banner.txt
+++ b/src/main/resources/banner.txt
@@ -1,5 +1,8 @@
====================================================================================================================
-
- Powered By whgojp
+ __ _____ __ __
+ / /___ __ ______ _/ ___/___ _____/ / ____ _/ /_
+ __ / / __ `/ | / / __ `/\__ \/ _ \/ ___/ / / __ `/ __ \
+ / /_/ / /_/ /| |/ / /_/ /___/ / __/ /__/ /___/ /_/ / /_/ /
+ \____/\__,_/ |___/\__,_//____/\___/\___/_____/\__,_/_.___/
====================================================================================================================
\ No newline at end of file
diff --git a/src/main/resources/mapper/LogMapper.xml b/src/main/resources/mapper/LogMapper.xml
deleted file mode 100644
index 165a1b1..0000000
--- a/src/main/resources/mapper/LogMapper.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- logId,username,optionName,
- optionTerminal,optionIp,optionTime
-
-
diff --git a/src/main/resources/mapper/SqliMapper.xml b/src/main/resources/mapper/SqliMapper.xml
index b27d600..a977910 100644
--- a/src/main/resources/mapper/SqliMapper.xml
+++ b/src/main/resources/mapper/SqliMapper.xml
@@ -14,8 +14,8 @@
id,username,password
insert into sqli (id,username,password) values (#{id,jdbcType=INTEGER},#{username,jdbcType=VARCHAR},#{password,jdbcType=VARCHAR})
@@ -33,7 +33,7 @@
-
+
SELECT * FROM sqli
@@ -41,14 +41,14 @@
-
+
SELECT * FROM sqli
ORDER BY #{field}
-
+
SELECT * FROM sqli
diff --git a/src/main/resources/static/api/clear.json b/src/main/resources/static/api/clear.json
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/api/init.json b/src/main/resources/static/api/init.json
old mode 100644
new mode 100755
index 495a46f..a1cd396
--- a/src/main/resources/static/api/init.json
+++ b/src/main/resources/static/api/init.json
@@ -101,13 +101,13 @@
},
{
"title": "Hibernate",
- "href": "",
+ "href": "sqli/hibernate",
"icon": "iconfont icon-Hivebiao",
"target": "_self"
},
{
"title": "JPA",
- "href": "",
+ "href": "sqli/jpa",
"icon": "iconfont icon-spring",
"target": "_self"
}
@@ -245,12 +245,13 @@
},
{
"title": "支付漏洞",
- "href": "",
+ "href": "logic/pay",
"icon": "iconfont icon-zhifu",
"target": "_self"
- }, {
+ },
+ {
"title": "并发安全",
- "href": "",
+ "href": "logic/concurrent",
"icon": "iconfont icon-gaobingfa",
"target": "_self"
},
@@ -380,7 +381,7 @@
},
{
"title": "凭证安全",
- "href": "",
+ "href": "/loginconfront/credential",
"icon": "iconfont icon-quanxianweizao",
"target": "_self"
}
@@ -477,7 +478,8 @@
}
]
}
+
]
}
]
-}
\ No newline at end of file
+}
diff --git a/src/main/resources/static/api/menus.json b/src/main/resources/static/api/menus.json
deleted file mode 100644
index e14d00e..0000000
--- a/src/main/resources/static/api/menus.json
+++ /dev/null
@@ -1,254 +0,0 @@
-{
- "code": 0,
- "msg": "",
- "count": 19,
- "data": [
- {
- "authorityId": 1,
- "authorityName": "系统管理",
- "orderNumber": 1,
- "menuUrl": null,
- "menuIcon": "layui-icon-set",
- "createTime": "2018/06/29 11:05:41",
- "authority": null,
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 0,
- "parentId": -1
- },
- {
- "authorityId": 2,
- "authorityName": "用户管理",
- "orderNumber": 2,
- "menuUrl": "system/user",
- "menuIcon": null,
- "createTime": "2018/06/29 11:05:41",
- "authority": null,
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 0,
- "parentId": 1
- },
- {
- "authorityId": 3,
- "authorityName": "查询用户",
- "orderNumber": 3,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/07/21 13:54:16",
- "authority": "user:view",
- "checked": 0,
- "updateTime": "2018/07/21 13:54:16",
- "isMenu": 1,
- "parentId": 2
- },
- {
- "authorityId": 4,
- "authorityName": "添加用户",
- "orderNumber": 4,
- "menuUrl": null,
- "menuIcon": null,
- "createTime": "2018/06/29 11:05:41",
- "authority": "user:add",
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 1,
- "parentId": 2
- },
- {
- "authorityId": 5,
- "authorityName": "修改用户",
- "orderNumber": 5,
- "menuUrl": null,
- "menuIcon": null,
- "createTime": "2018/06/29 11:05:41",
- "authority": "user:edit",
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 1,
- "parentId": 2
- },
- {
- "authorityId": 6,
- "authorityName": "删除用户",
- "orderNumber": 6,
- "menuUrl": null,
- "menuIcon": null,
- "createTime": "2018/06/29 11:05:41",
- "authority": "user:delete",
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 1,
- "parentId": 2
- },
- {
- "authorityId": 7,
- "authorityName": "角色管理",
- "orderNumber": 7,
- "menuUrl": "system/role",
- "menuIcon": null,
- "createTime": "2018/06/29 11:05:41",
- "authority": null,
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 0,
- "parentId": 1
- },
- {
- "authorityId": 8,
- "authorityName": "查询角色",
- "orderNumber": 8,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/07/21 13:54:59",
- "authority": "role:view",
- "checked": 0,
- "updateTime": "2018/07/21 13:54:58",
- "isMenu": 1,
- "parentId": 7
- },
- {
- "authorityId": 9,
- "authorityName": "添加角色",
- "orderNumber": 9,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/06/29 11:05:41",
- "authority": "role:add",
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 1,
- "parentId": 7
- },
- {
- "authorityId": 10,
- "authorityName": "修改角色",
- "orderNumber": 10,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/06/29 11:05:41",
- "authority": "role:edit",
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 1,
- "parentId": 7
- },
- {
- "authorityId": 11,
- "authorityName": "删除角色",
- "orderNumber": 11,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/06/29 11:05:41",
- "authority": "role:delete",
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 1,
- "parentId": 7
- },
- {
- "authorityId": 12,
- "authorityName": "角色权限管理",
- "orderNumber": 12,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/06/29 11:05:41",
- "authority": "role:auth",
- "checked": 0,
- "updateTime": "2018/07/13 15:27:18",
- "isMenu": 1,
- "parentId": 7
- },
- {
- "authorityId": 13,
- "authorityName": "权限管理",
- "orderNumber": 13,
- "menuUrl": "system/authorities",
- "menuIcon": null,
- "createTime": "2018/06/29 11:05:41",
- "authority": null,
- "checked": 0,
- "updateTime": "2018/07/13 15:45:13",
- "isMenu": 0,
- "parentId": 1
- },
- {
- "authorityId": 14,
- "authorityName": "查询权限",
- "orderNumber": 14,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/07/21 13:55:57",
- "authority": "authorities:view",
- "checked": 0,
- "updateTime": "2018/07/21 13:55:56",
- "isMenu": 1,
- "parentId": 13
- },
- {
- "authorityId": 15,
- "authorityName": "添加权限",
- "orderNumber": 15,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/06/29 11:05:41",
- "authority": "authorities:add",
- "checked": 0,
- "updateTime": "2018/06/29 11:05:41",
- "isMenu": 1,
- "parentId": 13
- },
- {
- "authorityId": 16,
- "authorityName": "修改权限",
- "orderNumber": 16,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/07/13 09:13:42",
- "authority": "authorities:edit",
- "checked": 0,
- "updateTime": "2018/07/13 09:13:42",
- "isMenu": 1,
- "parentId": 13
- },
- {
- "authorityId": 17,
- "authorityName": "删除权限",
- "orderNumber": 17,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/06/29 11:05:41",
- "authority": "authorities:delete",
- "checked": 0,
- "updateTime": "2018/06/29 11:05:41",
- "isMenu": 1,
- "parentId": 13
- },
- {
- "authorityId": 18,
- "authorityName": "登录日志",
- "orderNumber": 18,
- "menuUrl": "system/loginRecord",
- "menuIcon": null,
- "createTime": "2018/06/29 11:05:41",
- "authority": null,
- "checked": 0,
- "updateTime": "2018/06/29 11:05:41",
- "isMenu": 0,
- "parentId": 1
- },
- {
- "authorityId": 19,
- "authorityName": "查询登录日志",
- "orderNumber": 19,
- "menuUrl": "",
- "menuIcon": "",
- "createTime": "2018/07/21 13:56:43",
- "authority": "loginRecord:view",
- "checked": 0,
- "updateTime": "2018/07/21 13:56:43",
- "isMenu": 1,
- "parentId": 18
- }
- ]
-}
\ No newline at end of file
diff --git a/src/main/resources/static/api/table.json b/src/main/resources/static/api/table.json
deleted file mode 100644
index 7bda61b..0000000
--- a/src/main/resources/static/api/table.json
+++ /dev/null
@@ -1,127 +0,0 @@
-{
- "code": 0,
- "msg": "",
- "count": 1000,
- "data": [
- {
- "id": 10000,
- "username": "user-0",
- "sex": "女",
- "city": "城市-0",
- "sign": "签名-0",
- "experience": 255,
- "logins": 24,
- "wealth": 82830700,
- "classify": "作家",
- "score": 57
- },
- {
- "id": 10001,
- "username": "user-1",
- "sex": "男",
- "city": "城市-1",
- "sign": "签名-1",
- "experience": 884,
- "logins": 58,
- "wealth": 64928690,
- "classify": "词人",
- "score": 27
- },
- {
- "id": 10002,
- "username": "user-2",
- "sex": "女",
- "city": "城市-2",
- "sign": "签名-2",
- "experience": 650,
- "logins": 77,
- "wealth": 6298078,
- "classify": "酱油",
- "score": 31
- },
- {
- "id": 10003,
- "username": "user-3",
- "sex": "女",
- "city": "城市-3",
- "sign": "签名-3",
- "experience": 362,
- "logins": 157,
- "wealth": 37117017,
- "classify": "诗人",
- "score": 68
- },
- {
- "id": 10004,
- "username": "user-4",
- "sex": "男",
- "city": "城市-4",
- "sign": "签名-4",
- "experience": 807,
- "logins": 51,
- "wealth": 76263262,
- "classify": "作家",
- "score": 6
- },
- {
- "id": 10005,
- "username": "user-5",
- "sex": "女",
- "city": "城市-5",
- "sign": "签名-5",
- "experience": 173,
- "logins": 68,
- "wealth": 60344147,
- "classify": "作家",
- "score": 87
- },
- {
- "id": 10006,
- "username": "user-6",
- "sex": "女",
- "city": "城市-6",
- "sign": "签名-6",
- "experience": 982,
- "logins": 37,
- "wealth": 57768166,
- "classify": "作家",
- "score": 34
- },
- {
- "id": 10007,
- "username": "user-7",
- "sex": "男",
- "city": "城市-7",
- "sign": "签名-7",
- "experience": 727,
- "logins": 150,
- "wealth": 82030578,
- "classify": "作家",
- "score": 28
- },
- {
- "id": 10008,
- "username": "user-8",
- "sex": "男",
- "city": "城市-8",
- "sign": "签名-8",
- "experience": 951,
- "logins": 133,
- "wealth": 16503371,
- "classify": "词人",
- "score": 14
- },
- {
- "id": 10009,
- "username": "user-9",
- "sex": "女",
- "city": "城市-9",
- "sign": "签名-9",
- "experience": 484,
- "logins": 25,
- "wealth": 86801934,
- "classify": "词人",
- "score": 75
- }
- ]
-}
\ No newline at end of file
diff --git a/src/main/resources/static/api/tableSelect.json b/src/main/resources/static/api/tableSelect.json
deleted file mode 100644
index 37fb0ed..0000000
--- a/src/main/resources/static/api/tableSelect.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "code": 0,
- "msg": "",
- "count": 16,
- "data": [
- { "id":"001", "username":"张玉林", "sex":"女" },
- { "id":"002", "username":"刘晓军", "sex":"男" },
- { "id":"003", "username":"张恒", "sex":"男" },
- { "id":"004", "username":"朱一", "sex":"男" },
- { "id":"005", "username":"刘佳能", "sex":"女" },
- { "id":"006", "username":"晓梅", "sex":"女" },
- { "id":"007", "username":"马冬梅", "sex":"女" },
- { "id":"008", "username":"刘晓庆", "sex":"女" },
- { "id":"009", "username":"刘晓庆", "sex":"女" },
- { "id":"010", "username":"刘晓庆", "sex":"女" },
- { "id":"011", "username":"刘晓庆", "sex":"女" },
- { "id":"012", "username":"刘晓庆", "sex":"女" },
- { "id":"013", "username":"刘晓庆", "sex":"女" },
- { "id":"014", "username":"刘晓庆", "sex":"女" },
- { "id":"015", "username":"刘晓庆", "sex":"女" },
- { "id":"016", "username":"刘晓庆", "sex":"女" }
- ]
-}
\ No newline at end of file
diff --git a/src/main/resources/static/api/upload.json b/src/main/resources/static/api/upload.json
deleted file mode 100644
index 691902d..0000000
--- a/src/main/resources/static/api/upload.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "code": 1,
- "msg": "上传成功",
- "data": {
- "url": [
- "../images/logo.png",
- "../images/captcha.jpg"
- ]
- }
-}
diff --git a/src/main/resources/static/css/juejin.css b/src/main/resources/static/css/juejin.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/css/juejinsafe.css b/src/main/resources/static/css/juejinsafe.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/css/layuimini.css b/src/main/resources/static/css/layuimini.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/css/public.css b/src/main/resources/static/css/public.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/css/themes/default.css b/src/main/resources/static/css/themes/default.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/bg.jpg b/src/main/resources/static/images/bg.jpg
deleted file mode 100644
index 82b853e..0000000
Binary files a/src/main/resources/static/images/bg.jpg and /dev/null differ
diff --git a/src/main/resources/static/images/home.png b/src/main/resources/static/images/home.png
deleted file mode 100644
index 348ff27..0000000
Binary files a/src/main/resources/static/images/home.png and /dev/null differ
diff --git a/src/main/resources/static/images/icon-login.png b/src/main/resources/static/images/icon-login.png
deleted file mode 100644
index 1db2f96..0000000
Binary files a/src/main/resources/static/images/icon-login.png and /dev/null differ
diff --git a/src/main/resources/static/images/loginbg.png b/src/main/resources/static/images/loginbg.png
deleted file mode 100644
index 675c74b..0000000
Binary files a/src/main/resources/static/images/loginbg.png and /dev/null differ
diff --git a/src/main/resources/static/images/vul/components/deserialize.jpg b/src/main/resources/static/images/vul/components/deserialize.jpg
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/components/fastjson.png b/src/main/resources/static/images/vul/components/fastjson.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/components/log4j.png b/src/main/resources/static/images/vul/components/log4j.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/components/shiro.png b/src/main/resources/static/images/vul/components/shiro.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/crossOrigin/sameOrign.png b/src/main/resources/static/images/vul/crossOrigin/sameOrign.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/csrf/csrf.png b/src/main/resources/static/images/vul/csrf/csrf.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/dos/dos.jpeg b/src/main/resources/static/images/vul/dos/dos.jpeg
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/idor/idor.png b/src/main/resources/static/images/vul/idor/idor.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/jdbc/jdbc.png b/src/main/resources/static/images/vul/jdbc/jdbc.png
new file mode 100755
index 0000000..a4cf54f
Binary files /dev/null and b/src/main/resources/static/images/vul/jdbc/jdbc.png differ
diff --git a/src/main/resources/static/images/vul/memshell/filter.png b/src/main/resources/static/images/vul/memshell/filter.png
new file mode 100755
index 0000000..8b13789
--- /dev/null
+++ b/src/main/resources/static/images/vul/memshell/filter.png
@@ -0,0 +1 @@
+
diff --git a/src/main/resources/static/images/vul/memshell/listener.png b/src/main/resources/static/images/vul/memshell/listener.png
new file mode 100755
index 0000000..8b13789
--- /dev/null
+++ b/src/main/resources/static/images/vul/memshell/listener.png
@@ -0,0 +1 @@
+
diff --git a/src/main/resources/static/images/vul/memshell/servlet.png b/src/main/resources/static/images/vul/memshell/servlet.png
new file mode 100755
index 0000000..8b13789
--- /dev/null
+++ b/src/main/resources/static/images/vul/memshell/servlet.png
@@ -0,0 +1 @@
+
diff --git a/src/main/resources/static/images/vul/ssrf/ssrf.jpg b/src/main/resources/static/images/vul/ssrf/ssrf.jpg
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/xss/dom.png b/src/main/resources/static/images/vul/xss/dom.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/xss/reflect.png b/src/main/resources/static/images/vul/xss/reflect.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/xss/store.jpg b/src/main/resources/static/images/vul/xss/store.jpg
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/images/vul/xxe/xxe.png b/src/main/resources/static/images/vul/xxe/xxe.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/hackcookie.js b/src/main/resources/static/js/hackcookie.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/header.js b/src/main/resources/static/js/header.js
old mode 100644
new mode 100755
index 0407df9..e7f3afb
--- a/src/main/resources/static/js/header.js
+++ b/src/main/resources/static/js/header.js
@@ -24,4 +24,4 @@ document.writeln("");
document.writeln("");
document.writeln("");
document.writeln("");
-document.writeln("");
+document.writeln("");
diff --git a/src/main/resources/static/js/jquery.request.js b/src/main/resources/static/js/jquery.request.js
old mode 100644
new mode 100755
index f4260aa..8002161
--- a/src/main/resources/static/js/jquery.request.js
+++ b/src/main/resources/static/js/jquery.request.js
@@ -42,7 +42,10 @@ function request (url, method, data = {}, contentType, back){
error: error,
headers: xhr.getAllResponseHeaders()
});
- return typeof back === "function" && back(null);
+ var message = xhr.responseJSON && xhr.responseJSON.msg
+ ? xhr.responseJSON.msg
+ : "请求失败:" + (xhr.status || status) + " " + (error || xhr.statusText || "");
+ return typeof back === "function" && back({code: 1, msg: message});
}
});
};
@@ -57,4 +60,3 @@ function postAjaxRequst (url, data, callBack) {
return typeof callBack == "function" && callBack(res)
})
};
-
diff --git a/src/main/resources/static/js/jsencrypt.min.js b/src/main/resources/static/js/jsencrypt.min.js
new file mode 100755
index 0000000..c2b6b10
--- /dev/null
+++ b/src/main/resources/static/js/jsencrypt.min.js
@@ -0,0 +1,1540 @@
+/*! For license information please see jsencrypt.min.js.LICENSE.txt */
+!function (t, e) {
+ "object" == typeof exports && "object" == typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define([], e) : "object" == typeof exports ? exports.JSEncrypt = e() : t.JSEncrypt = e()
+}(window, (function () {
+ return (() => {
+ "use strict";
+ var t = {
+ 771: (t, e, i) => {
+ function r(t) {
+ return "0123456789abcdefghijklmnopqrstuvwxyz".charAt(t)
+ }
+
+ function n(t, e) {
+ return t & e
+ }
+
+ function s(t, e) {
+ return t | e
+ }
+
+ function o(t, e) {
+ return t ^ e
+ }
+
+ function h(t, e) {
+ return t & ~e
+ }
+
+ function a(t) {
+ if (0 == t) return -1;
+ var e = 0;
+ return 0 == (65535 & t) && (t >>= 16, e += 16), 0 == (255 & t) && (t >>= 8, e += 8), 0 == (15 & t) && (t >>= 4, e += 4), 0 == (3 & t) && (t >>= 2, e += 2), 0 == (1 & t) && ++e, e
+ }
+
+ function u(t) {
+ for (var e = 0; 0 != t;) t &= t - 1, ++e;
+ return e
+ }
+
+ i.d(e, {default: () => nt});
+ var c, f = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ function l(t) {
+ var e, i, r = "";
+ for (e = 0; e + 3 <= t.length; e += 3) i = parseInt(t.substring(e, e + 3), 16), r += f.charAt(i >> 6) + f.charAt(63 & i);
+ for (e + 1 == t.length ? (i = parseInt(t.substring(e, e + 1), 16), r += f.charAt(i << 2)) : e + 2 == t.length && (i = parseInt(t.substring(e, e + 2), 16), r += f.charAt(i >> 2) + f.charAt((3 & i) << 4)); (3 & r.length) > 0;) r += "=";
+ return r
+ }
+
+ function p(t) {
+ var e, i = "", n = 0, s = 0;
+ for (e = 0; e < t.length && "=" != t.charAt(e); ++e) {
+ var o = f.indexOf(t.charAt(e));
+ o < 0 || (0 == n ? (i += r(o >> 2), s = 3 & o, n = 1) : 1 == n ? (i += r(s << 2 | o >> 4), s = 15 & o, n = 2) : 2 == n ? (i += r(s), i += r(o >> 2), s = 3 & o, n = 3) : (i += r(s << 2 | o >> 4), i += r(15 & o), n = 0))
+ }
+ return 1 == n && (i += r(s << 2)), i
+ }
+
+ var g, d = {
+ decode: function (t) {
+ var e;
+ if (void 0 === g) {
+ var i = "= \f\n\r\t \u2028\u2029";
+ for (g = Object.create(null), e = 0; e < 64; ++e) g["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(e)] = e;
+ for (g["-"] = 62, g._ = 63, e = 0; e < i.length; ++e) g[i.charAt(e)] = -1
+ }
+ var r = [], n = 0, s = 0;
+ for (e = 0; e < t.length; ++e) {
+ var o = t.charAt(e);
+ if ("=" == o) break;
+ if (-1 != (o = g[o])) {
+ if (void 0 === o) throw new Error("Illegal character at offset " + e);
+ n |= o, ++s >= 4 ? (r[r.length] = n >> 16, r[r.length] = n >> 8 & 255, r[r.length] = 255 & n, n = 0, s = 0) : n <<= 6
+ }
+ }
+ switch (s) {
+ case 1:
+ throw new Error("Base64 encoding incomplete: at least 2 bits missing");
+ case 2:
+ r[r.length] = n >> 10;
+ break;
+ case 3:
+ r[r.length] = n >> 16, r[r.length] = n >> 8 & 255
+ }
+ return r
+ },
+ re: /-----BEGIN [^-]+-----([A-Za-z0-9+\/=\s]+)-----END [^-]+-----|begin-base64[^\n]+\n([A-Za-z0-9+\/=\s]+)====/,
+ unarmor: function (t) {
+ var e = d.re.exec(t);
+ if (e) if (e[1]) t = e[1]; else {
+ if (!e[2]) throw new Error("RegExp out of sync");
+ t = e[2]
+ }
+ return d.decode(t)
+ }
+ }, v = 1e13, m = function () {
+ function t(t) {
+ this.buf = [+t || 0]
+ }
+
+ return t.prototype.mulAdd = function (t, e) {
+ var i, r, n = this.buf, s = n.length;
+ for (i = 0; i < s; ++i) (r = n[i] * t + e) < v ? e = 0 : r -= (e = 0 | r / v) * v, n[i] = r;
+ e > 0 && (n[i] = e)
+ }, t.prototype.sub = function (t) {
+ var e, i, r = this.buf, n = r.length;
+ for (e = 0; e < n; ++e) (i = r[e] - t) < 0 ? (i += v, t = 1) : t = 0, r[e] = i;
+ for (; 0 === r[r.length - 1];) r.pop()
+ }, t.prototype.toString = function (t) {
+ if (10 != (t || 10)) throw new Error("only base 10 is supported");
+ for (var e = this.buf, i = e[e.length - 1].toString(), r = e.length - 2; r >= 0; --r) i += (v + e[r]).toString().substring(1);
+ return i
+ }, t.prototype.valueOf = function () {
+ for (var t = this.buf, e = 0, i = t.length - 1; i >= 0; --i) e = e * v + t[i];
+ return e
+ }, t.prototype.simplify = function () {
+ var t = this.buf;
+ return 1 == t.length ? t[0] : this
+ }, t
+ }(),
+ y = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/,
+ b = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/;
+
+ function T(t, e) {
+ return t.length > e && (t = t.substring(0, e) + "…"), t
+ }
+
+ var S, E = function () {
+ function t(e, i) {
+ this.hexDigits = "0123456789ABCDEF", e instanceof t ? (this.enc = e.enc, this.pos = e.pos) : (this.enc = e, this.pos = i)
+ }
+
+ return t.prototype.get = function (t) {
+ if (void 0 === t && (t = this.pos++), t >= this.enc.length) throw new Error("Requesting byte offset " + t + " on a stream of length " + this.enc.length);
+ return "string" == typeof this.enc ? this.enc.charCodeAt(t) : this.enc[t]
+ }, t.prototype.hexByte = function (t) {
+ return this.hexDigits.charAt(t >> 4 & 15) + this.hexDigits.charAt(15 & t)
+ }, t.prototype.hexDump = function (t, e, i) {
+ for (var r = "", n = t; n < e; ++n) if (r += this.hexByte(this.get(n)), !0 !== i) switch (15 & n) {
+ case 7:
+ r += " ";
+ break;
+ case 15:
+ r += "\n";
+ break;
+ default:
+ r += " "
+ }
+ return r
+ }, t.prototype.isASCII = function (t, e) {
+ for (var i = t; i < e; ++i) {
+ var r = this.get(i);
+ if (r < 32 || r > 176) return !1
+ }
+ return !0
+ }, t.prototype.parseStringISO = function (t, e) {
+ for (var i = "", r = t; r < e; ++r) i += String.fromCharCode(this.get(r));
+ return i
+ }, t.prototype.parseStringUTF = function (t, e) {
+ for (var i = "", r = t; r < e;) {
+ var n = this.get(r++);
+ i += n < 128 ? String.fromCharCode(n) : n > 191 && n < 224 ? String.fromCharCode((31 & n) << 6 | 63 & this.get(r++)) : String.fromCharCode((15 & n) << 12 | (63 & this.get(r++)) << 6 | 63 & this.get(r++))
+ }
+ return i
+ }, t.prototype.parseStringBMP = function (t, e) {
+ for (var i, r, n = "", s = t; s < e;) i = this.get(s++), r = this.get(s++), n += String.fromCharCode(i << 8 | r);
+ return n
+ }, t.prototype.parseTime = function (t, e, i) {
+ var r = this.parseStringISO(t, e), n = (i ? y : b).exec(r);
+ return n ? (i && (n[1] = +n[1], n[1] += +n[1] < 70 ? 2e3 : 1900), r = n[1] + "-" + n[2] + "-" + n[3] + " " + n[4], n[5] && (r += ":" + n[5], n[6] && (r += ":" + n[6], n[7] && (r += "." + n[7]))), n[8] && (r += " UTC", "Z" != n[8] && (r += n[8], n[9] && (r += ":" + n[9]))), r) : "Unrecognized time: " + r
+ }, t.prototype.parseInteger = function (t, e) {
+ for (var i, r = this.get(t), n = r > 127, s = n ? 255 : 0, o = ""; r == s && ++t < e;) r = this.get(t);
+ if (0 == (i = e - t)) return n ? -1 : 0;
+ if (i > 4) {
+ for (o = r, i <<= 3; 0 == (128 & (+o ^ s));) o = +o << 1, --i;
+ o = "(" + i + " bit)\n"
+ }
+ n && (r -= 256);
+ for (var h = new m(r), a = t + 1; a < e; ++a) h.mulAdd(256, this.get(a));
+ return o + h.toString()
+ }, t.prototype.parseBitString = function (t, e, i) {
+ for (var r = this.get(t), n = "(" + ((e - t - 1 << 3) - r) + " bit)\n", s = "", o = t + 1; o < e; ++o) {
+ for (var h = this.get(o), a = o == e - 1 ? r : 0, u = 7; u >= a; --u) s += h >> u & 1 ? "1" : "0";
+ if (s.length > i) return n + T(s, i)
+ }
+ return n + s
+ }, t.prototype.parseOctetString = function (t, e, i) {
+ if (this.isASCII(t, e)) return T(this.parseStringISO(t, e), i);
+ var r = e - t, n = "(" + r + " byte)\n";
+ r > (i /= 2) && (e = t + i);
+ for (var s = t; s < e; ++s) n += this.hexByte(this.get(s));
+ return r > i && (n += "…"), n
+ }, t.prototype.parseOID = function (t, e, i) {
+ for (var r = "", n = new m, s = 0, o = t; o < e; ++o) {
+ var h = this.get(o);
+ if (n.mulAdd(128, 127 & h), s += 7, !(128 & h)) {
+ if ("" === r) if ((n = n.simplify()) instanceof m) n.sub(80), r = "2." + n.toString(); else {
+ var a = n < 80 ? n < 40 ? 0 : 1 : 2;
+ r = a + "." + (n - 40 * a)
+ } else r += "." + n.toString();
+ if (r.length > i) return T(r, i);
+ n = new m, s = 0
+ }
+ }
+ return s > 0 && (r += ".incomplete"), r
+ }, t
+ }(), w = function () {
+ function t(t, e, i, r, n) {
+ if (!(r instanceof D)) throw new Error("Invalid tag value.");
+ this.stream = t, this.header = e, this.length = i, this.tag = r, this.sub = n
+ }
+
+ return t.prototype.typeName = function () {
+ switch (this.tag.tagClass) {
+ case 0:
+ switch (this.tag.tagNumber) {
+ case 0:
+ return "EOC";
+ case 1:
+ return "BOOLEAN";
+ case 2:
+ return "INTEGER";
+ case 3:
+ return "BIT_STRING";
+ case 4:
+ return "OCTET_STRING";
+ case 5:
+ return "NULL";
+ case 6:
+ return "OBJECT_IDENTIFIER";
+ case 7:
+ return "ObjectDescriptor";
+ case 8:
+ return "EXTERNAL";
+ case 9:
+ return "REAL";
+ case 10:
+ return "ENUMERATED";
+ case 11:
+ return "EMBEDDED_PDV";
+ case 12:
+ return "UTF8String";
+ case 16:
+ return "SEQUENCE";
+ case 17:
+ return "SET";
+ case 18:
+ return "NumericString";
+ case 19:
+ return "PrintableString";
+ case 20:
+ return "TeletexString";
+ case 21:
+ return "VideotexString";
+ case 22:
+ return "IA5String";
+ case 23:
+ return "UTCTime";
+ case 24:
+ return "GeneralizedTime";
+ case 25:
+ return "GraphicString";
+ case 26:
+ return "VisibleString";
+ case 27:
+ return "GeneralString";
+ case 28:
+ return "UniversalString";
+ case 30:
+ return "BMPString"
+ }
+ return "Universal_" + this.tag.tagNumber.toString();
+ case 1:
+ return "Application_" + this.tag.tagNumber.toString();
+ case 2:
+ return "[" + this.tag.tagNumber.toString() + "]";
+ case 3:
+ return "Private_" + this.tag.tagNumber.toString()
+ }
+ }, t.prototype.content = function (t) {
+ if (void 0 === this.tag) return null;
+ void 0 === t && (t = 1 / 0);
+ var e = this.posContent(), i = Math.abs(this.length);
+ if (!this.tag.isUniversal()) return null !== this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseOctetString(e, e + i, t);
+ switch (this.tag.tagNumber) {
+ case 1:
+ return 0 === this.stream.get(e) ? "false" : "true";
+ case 2:
+ return this.stream.parseInteger(e, e + i);
+ case 3:
+ return this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseBitString(e, e + i, t);
+ case 4:
+ return this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseOctetString(e, e + i, t);
+ case 6:
+ return this.stream.parseOID(e, e + i, t);
+ case 16:
+ case 17:
+ return null !== this.sub ? "(" + this.sub.length + " elem)" : "(no elem)";
+ case 12:
+ return T(this.stream.parseStringUTF(e, e + i), t);
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 26:
+ return T(this.stream.parseStringISO(e, e + i), t);
+ case 30:
+ return T(this.stream.parseStringBMP(e, e + i), t);
+ case 23:
+ case 24:
+ return this.stream.parseTime(e, e + i, 23 == this.tag.tagNumber)
+ }
+ return null
+ }, t.prototype.toString = function () {
+ return this.typeName() + "@" + this.stream.pos + "[header:" + this.header + ",length:" + this.length + ",sub:" + (null === this.sub ? "null" : this.sub.length) + "]"
+ }, t.prototype.toPrettyString = function (t) {
+ void 0 === t && (t = "");
+ var e = t + this.typeName() + " @" + this.stream.pos;
+ if (this.length >= 0 && (e += "+"), e += this.length, this.tag.tagConstructed ? e += " (constructed)" : !this.tag.isUniversal() || 3 != this.tag.tagNumber && 4 != this.tag.tagNumber || null === this.sub || (e += " (encapsulates)"), e += "\n", null !== this.sub) {
+ t += " ";
+ for (var i = 0, r = this.sub.length; i < r; ++i) e += this.sub[i].toPrettyString(t)
+ }
+ return e
+ }, t.prototype.posStart = function () {
+ return this.stream.pos
+ }, t.prototype.posContent = function () {
+ return this.stream.pos + this.header
+ }, t.prototype.posEnd = function () {
+ return this.stream.pos + this.header + Math.abs(this.length)
+ }, t.prototype.toHexString = function () {
+ return this.stream.hexDump(this.posStart(), this.posEnd(), !0)
+ }, t.decodeLength = function (t) {
+ var e = t.get(), i = 127 & e;
+ if (i == e) return i;
+ if (i > 6) throw new Error("Length over 48 bits not supported at position " + (t.pos - 1));
+ if (0 === i) return null;
+ e = 0;
+ for (var r = 0; r < i; ++r) e = 256 * e + t.get();
+ return e
+ }, t.prototype.getHexStringValue = function () {
+ var t = this.toHexString(), e = 2 * this.header, i = 2 * this.length;
+ return t.substr(e, i)
+ }, t.decode = function (e) {
+ var i;
+ i = e instanceof E ? e : new E(e, 0);
+ var r = new E(i), n = new D(i), s = t.decodeLength(i), o = i.pos, h = o - r.pos, a = null,
+ u = function () {
+ var e = [];
+ if (null !== s) {
+ for (var r = o + s; i.pos < r;) e[e.length] = t.decode(i);
+ if (i.pos != r) throw new Error("Content size is not correct for container starting at offset " + o)
+ } else try {
+ for (; ;) {
+ var n = t.decode(i);
+ if (n.tag.isEOC()) break;
+ e[e.length] = n
+ }
+ s = o - i.pos
+ } catch (t) {
+ throw new Error("Exception while decoding undefined length content: " + t)
+ }
+ return e
+ };
+ if (n.tagConstructed) a = u(); else if (n.isUniversal() && (3 == n.tagNumber || 4 == n.tagNumber)) try {
+ if (3 == n.tagNumber && 0 != i.get()) throw new Error("BIT STRINGs with unused bits cannot encapsulate.");
+ a = u();
+ for (var c = 0; c < a.length; ++c) if (a[c].tag.isEOC()) throw new Error("EOC is not supposed to be actual content.")
+ } catch (t) {
+ a = null
+ }
+ if (null === a) {
+ if (null === s) throw new Error("We can't skip over an invalid tag with undefined length at offset " + o);
+ i.pos = o + Math.abs(s)
+ }
+ return new t(r, h, s, n, a)
+ }, t
+ }(), D = function () {
+ function t(t) {
+ var e = t.get();
+ if (this.tagClass = e >> 6, this.tagConstructed = 0 != (32 & e), this.tagNumber = 31 & e, 31 == this.tagNumber) {
+ var i = new m;
+ do {
+ e = t.get(), i.mulAdd(128, 127 & e)
+ } while (128 & e);
+ this.tagNumber = i.simplify()
+ }
+ }
+
+ return t.prototype.isUniversal = function () {
+ return 0 === this.tagClass
+ }, t.prototype.isEOC = function () {
+ return 0 === this.tagClass && 0 === this.tagNumber
+ }, t
+ }(),
+ x = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997],
+ R = (1 << 26) / x[x.length - 1], B = function () {
+ function t(t, e, i) {
+ null != t && ("number" == typeof t ? this.fromNumber(t, e, i) : null == e && "string" != typeof t ? this.fromString(t, 256) : this.fromString(t, e))
+ }
+
+ return t.prototype.toString = function (t) {
+ if (this.s < 0) return "-" + this.negate().toString(t);
+ var e;
+ if (16 == t) e = 4; else if (8 == t) e = 3; else if (2 == t) e = 1; else if (32 == t) e = 5; else {
+ if (4 != t) return this.toRadix(t);
+ e = 2
+ }
+ var i, n = (1 << e) - 1, s = !1, o = "", h = this.t, a = this.DB - h * this.DB % e;
+ if (h-- > 0) for (a < this.DB && (i = this[h] >> a) > 0 && (s = !0, o = r(i)); h >= 0;) a < e ? (i = (this[h] & (1 << a) - 1) << e - a, i |= this[--h] >> (a += this.DB - e)) : (i = this[h] >> (a -= e) & n, a <= 0 && (a += this.DB, --h)), i > 0 && (s = !0), s && (o += r(i));
+ return s ? o : "0"
+ }, t.prototype.negate = function () {
+ var e = N();
+ return t.ZERO.subTo(this, e), e
+ }, t.prototype.abs = function () {
+ return this.s < 0 ? this.negate() : this
+ }, t.prototype.compareTo = function (t) {
+ var e = this.s - t.s;
+ if (0 != e) return e;
+ var i = this.t;
+ if (0 != (e = i - t.t)) return this.s < 0 ? -e : e;
+ for (; --i >= 0;) if (0 != (e = this[i] - t[i])) return e;
+ return 0
+ }, t.prototype.bitLength = function () {
+ return this.t <= 0 ? 0 : this.DB * (this.t - 1) + F(this[this.t - 1] ^ this.s & this.DM)
+ }, t.prototype.mod = function (e) {
+ var i = N();
+ return this.abs().divRemTo(e, null, i), this.s < 0 && i.compareTo(t.ZERO) > 0 && e.subTo(i, i), i
+ }, t.prototype.modPowInt = function (t, e) {
+ var i;
+ return i = t < 256 || e.isEven() ? new A(e) : new V(e), this.exp(t, i)
+ }, t.prototype.clone = function () {
+ var t = N();
+ return this.copyTo(t), t
+ }, t.prototype.intValue = function () {
+ if (this.s < 0) {
+ if (1 == this.t) return this[0] - this.DV;
+ if (0 == this.t) return -1
+ } else {
+ if (1 == this.t) return this[0];
+ if (0 == this.t) return 0
+ }
+ return (this[1] & (1 << 32 - this.DB) - 1) << this.DB | this[0]
+ }, t.prototype.byteValue = function () {
+ return 0 == this.t ? this.s : this[0] << 24 >> 24
+ }, t.prototype.shortValue = function () {
+ return 0 == this.t ? this.s : this[0] << 16 >> 16
+ }, t.prototype.signum = function () {
+ return this.s < 0 ? -1 : this.t <= 0 || 1 == this.t && this[0] <= 0 ? 0 : 1
+ }, t.prototype.toByteArray = function () {
+ var t = this.t, e = [];
+ e[0] = this.s;
+ var i, r = this.DB - t * this.DB % 8, n = 0;
+ if (t-- > 0) for (r < this.DB && (i = this[t] >> r) != (this.s & this.DM) >> r && (e[n++] = i | this.s << this.DB - r); t >= 0;) r < 8 ? (i = (this[t] & (1 << r) - 1) << 8 - r, i |= this[--t] >> (r += this.DB - 8)) : (i = this[t] >> (r -= 8) & 255, r <= 0 && (r += this.DB, --t)), 0 != (128 & i) && (i |= -256), 0 == n && (128 & this.s) != (128 & i) && ++n, (n > 0 || i != this.s) && (e[n++] = i);
+ return e
+ }, t.prototype.equals = function (t) {
+ return 0 == this.compareTo(t)
+ }, t.prototype.min = function (t) {
+ return this.compareTo(t) < 0 ? this : t
+ }, t.prototype.max = function (t) {
+ return this.compareTo(t) > 0 ? this : t
+ }, t.prototype.and = function (t) {
+ var e = N();
+ return this.bitwiseTo(t, n, e), e
+ }, t.prototype.or = function (t) {
+ var e = N();
+ return this.bitwiseTo(t, s, e), e
+ }, t.prototype.xor = function (t) {
+ var e = N();
+ return this.bitwiseTo(t, o, e), e
+ }, t.prototype.andNot = function (t) {
+ var e = N();
+ return this.bitwiseTo(t, h, e), e
+ }, t.prototype.not = function () {
+ for (var t = N(), e = 0; e < this.t; ++e) t[e] = this.DM & ~this[e];
+ return t.t = this.t, t.s = ~this.s, t
+ }, t.prototype.shiftLeft = function (t) {
+ var e = N();
+ return t < 0 ? this.rShiftTo(-t, e) : this.lShiftTo(t, e), e
+ }, t.prototype.shiftRight = function (t) {
+ var e = N();
+ return t < 0 ? this.lShiftTo(-t, e) : this.rShiftTo(t, e), e
+ }, t.prototype.getLowestSetBit = function () {
+ for (var t = 0; t < this.t; ++t) if (0 != this[t]) return t * this.DB + a(this[t]);
+ return this.s < 0 ? this.t * this.DB : -1
+ }, t.prototype.bitCount = function () {
+ for (var t = 0, e = this.s & this.DM, i = 0; i < this.t; ++i) t += u(this[i] ^ e);
+ return t
+ }, t.prototype.testBit = function (t) {
+ var e = Math.floor(t / this.DB);
+ return e >= this.t ? 0 != this.s : 0 != (this[e] & 1 << t % this.DB)
+ }, t.prototype.setBit = function (t) {
+ return this.changeBit(t, s)
+ }, t.prototype.clearBit = function (t) {
+ return this.changeBit(t, h)
+ }, t.prototype.flipBit = function (t) {
+ return this.changeBit(t, o)
+ }, t.prototype.add = function (t) {
+ var e = N();
+ return this.addTo(t, e), e
+ }, t.prototype.subtract = function (t) {
+ var e = N();
+ return this.subTo(t, e), e
+ }, t.prototype.multiply = function (t) {
+ var e = N();
+ return this.multiplyTo(t, e), e
+ }, t.prototype.divide = function (t) {
+ var e = N();
+ return this.divRemTo(t, e, null), e
+ }, t.prototype.remainder = function (t) {
+ var e = N();
+ return this.divRemTo(t, null, e), e
+ }, t.prototype.divideAndRemainder = function (t) {
+ var e = N(), i = N();
+ return this.divRemTo(t, e, i), [e, i]
+ }, t.prototype.modPow = function (t, e) {
+ var i, r, n = t.bitLength(), s = C(1);
+ if (n <= 0) return s;
+ i = n < 18 ? 1 : n < 48 ? 3 : n < 144 ? 4 : n < 768 ? 5 : 6, r = n < 8 ? new A(e) : e.isEven() ? new I(e) : new V(e);
+ var o = [], h = 3, a = i - 1, u = (1 << i) - 1;
+ if (o[1] = r.convert(this), i > 1) {
+ var c = N();
+ for (r.sqrTo(o[1], c); h <= u;) o[h] = N(), r.mulTo(c, o[h - 2], o[h]), h += 2
+ }
+ var f, l, p = t.t - 1, g = !0, d = N();
+ for (n = F(t[p]) - 1; p >= 0;) {
+ for (n >= a ? f = t[p] >> n - a & u : (f = (t[p] & (1 << n + 1) - 1) << a - n, p > 0 && (f |= t[p - 1] >> this.DB + n - a)), h = i; 0 == (1 & f);) f >>= 1, --h;
+ if ((n -= h) < 0 && (n += this.DB, --p), g) o[f].copyTo(s), g = !1; else {
+ for (; h > 1;) r.sqrTo(s, d), r.sqrTo(d, s), h -= 2;
+ h > 0 ? r.sqrTo(s, d) : (l = s, s = d, d = l), r.mulTo(d, o[f], s)
+ }
+ for (; p >= 0 && 0 == (t[p] & 1 << n);) r.sqrTo(s, d), l = s, s = d, d = l, --n < 0 && (n = this.DB - 1, --p)
+ }
+ return r.revert(s)
+ }, t.prototype.modInverse = function (e) {
+ var i = e.isEven();
+ if (this.isEven() && i || 0 == e.signum()) return t.ZERO;
+ for (var r = e.clone(), n = this.clone(), s = C(1), o = C(0), h = C(0), a = C(1); 0 != r.signum();) {
+ for (; r.isEven();) r.rShiftTo(1, r), i ? (s.isEven() && o.isEven() || (s.addTo(this, s), o.subTo(e, o)), s.rShiftTo(1, s)) : o.isEven() || o.subTo(e, o), o.rShiftTo(1, o);
+ for (; n.isEven();) n.rShiftTo(1, n), i ? (h.isEven() && a.isEven() || (h.addTo(this, h), a.subTo(e, a)), h.rShiftTo(1, h)) : a.isEven() || a.subTo(e, a), a.rShiftTo(1, a);
+ r.compareTo(n) >= 0 ? (r.subTo(n, r), i && s.subTo(h, s), o.subTo(a, o)) : (n.subTo(r, n), i && h.subTo(s, h), a.subTo(o, a))
+ }
+ return 0 != n.compareTo(t.ONE) ? t.ZERO : a.compareTo(e) >= 0 ? a.subtract(e) : a.signum() < 0 ? (a.addTo(e, a), a.signum() < 0 ? a.add(e) : a) : a
+ }, t.prototype.pow = function (t) {
+ return this.exp(t, new O)
+ }, t.prototype.gcd = function (t) {
+ var e = this.s < 0 ? this.negate() : this.clone(), i = t.s < 0 ? t.negate() : t.clone();
+ if (e.compareTo(i) < 0) {
+ var r = e;
+ e = i, i = r
+ }
+ var n = e.getLowestSetBit(), s = i.getLowestSetBit();
+ if (s < 0) return e;
+ for (n < s && (s = n), s > 0 && (e.rShiftTo(s, e), i.rShiftTo(s, i)); e.signum() > 0;) (n = e.getLowestSetBit()) > 0 && e.rShiftTo(n, e), (n = i.getLowestSetBit()) > 0 && i.rShiftTo(n, i), e.compareTo(i) >= 0 ? (e.subTo(i, e), e.rShiftTo(1, e)) : (i.subTo(e, i), i.rShiftTo(1, i));
+ return s > 0 && i.lShiftTo(s, i), i
+ }, t.prototype.isProbablePrime = function (t) {
+ var e, i = this.abs();
+ if (1 == i.t && i[0] <= x[x.length - 1]) {
+ for (e = 0; e < x.length; ++e) if (i[0] == x[e]) return !0;
+ return !1
+ }
+ if (i.isEven()) return !1;
+ for (e = 1; e < x.length;) {
+ for (var r = x[e], n = e + 1; n < x.length && r < R;) r *= x[n++];
+ for (r = i.modInt(r); e < n;) if (r % x[e++] == 0) return !1
+ }
+ return i.millerRabin(t)
+ }, t.prototype.copyTo = function (t) {
+ for (var e = this.t - 1; e >= 0; --e) t[e] = this[e];
+ t.t = this.t, t.s = this.s
+ }, t.prototype.fromInt = function (t) {
+ this.t = 1, this.s = t < 0 ? -1 : 0, t > 0 ? this[0] = t : t < -1 ? this[0] = t + this.DV : this.t = 0
+ }, t.prototype.fromString = function (e, i) {
+ var r;
+ if (16 == i) r = 4; else if (8 == i) r = 3; else if (256 == i) r = 8; else if (2 == i) r = 1; else if (32 == i) r = 5; else {
+ if (4 != i) return void this.fromRadix(e, i);
+ r = 2
+ }
+ this.t = 0, this.s = 0;
+ for (var n = e.length, s = !1, o = 0; --n >= 0;) {
+ var h = 8 == r ? 255 & +e[n] : H(e, n);
+ h < 0 ? "-" == e.charAt(n) && (s = !0) : (s = !1, 0 == o ? this[this.t++] = h : o + r > this.DB ? (this[this.t - 1] |= (h & (1 << this.DB - o) - 1) << o, this[this.t++] = h >> this.DB - o) : this[this.t - 1] |= h << o, (o += r) >= this.DB && (o -= this.DB))
+ }
+ 8 == r && 0 != (128 & +e[0]) && (this.s = -1, o > 0 && (this[this.t - 1] |= (1 << this.DB - o) - 1 << o)), this.clamp(), s && t.ZERO.subTo(this, this)
+ }, t.prototype.clamp = function () {
+ for (var t = this.s & this.DM; this.t > 0 && this[this.t - 1] == t;) --this.t
+ }, t.prototype.dlShiftTo = function (t, e) {
+ var i;
+ for (i = this.t - 1; i >= 0; --i) e[i + t] = this[i];
+ for (i = t - 1; i >= 0; --i) e[i] = 0;
+ e.t = this.t + t, e.s = this.s
+ }, t.prototype.drShiftTo = function (t, e) {
+ for (var i = t; i < this.t; ++i) e[i - t] = this[i];
+ e.t = Math.max(this.t - t, 0), e.s = this.s
+ }, t.prototype.lShiftTo = function (t, e) {
+ for (var i = t % this.DB, r = this.DB - i, n = (1 << r) - 1, s = Math.floor(t / this.DB), o = this.s << i & this.DM, h = this.t - 1; h >= 0; --h) e[h + s + 1] = this[h] >> r | o, o = (this[h] & n) << i;
+ for (h = s - 1; h >= 0; --h) e[h] = 0;
+ e[s] = o, e.t = this.t + s + 1, e.s = this.s, e.clamp()
+ }, t.prototype.rShiftTo = function (t, e) {
+ e.s = this.s;
+ var i = Math.floor(t / this.DB);
+ if (i >= this.t) e.t = 0; else {
+ var r = t % this.DB, n = this.DB - r, s = (1 << r) - 1;
+ e[0] = this[i] >> r;
+ for (var o = i + 1; o < this.t; ++o) e[o - i - 1] |= (this[o] & s) << n, e[o - i] = this[o] >> r;
+ r > 0 && (e[this.t - i - 1] |= (this.s & s) << n), e.t = this.t - i, e.clamp()
+ }
+ }, t.prototype.subTo = function (t, e) {
+ for (var i = 0, r = 0, n = Math.min(t.t, this.t); i < n;) r += this[i] - t[i], e[i++] = r & this.DM, r >>= this.DB;
+ if (t.t < this.t) {
+ for (r -= t.s; i < this.t;) r += this[i], e[i++] = r & this.DM, r >>= this.DB;
+ r += this.s
+ } else {
+ for (r += this.s; i < t.t;) r -= t[i], e[i++] = r & this.DM, r >>= this.DB;
+ r -= t.s
+ }
+ e.s = r < 0 ? -1 : 0, r < -1 ? e[i++] = this.DV + r : r > 0 && (e[i++] = r), e.t = i, e.clamp()
+ }, t.prototype.multiplyTo = function (e, i) {
+ var r = this.abs(), n = e.abs(), s = r.t;
+ for (i.t = s + n.t; --s >= 0;) i[s] = 0;
+ for (s = 0; s < n.t; ++s) i[s + r.t] = r.am(0, n[s], i, s, 0, r.t);
+ i.s = 0, i.clamp(), this.s != e.s && t.ZERO.subTo(i, i)
+ }, t.prototype.squareTo = function (t) {
+ for (var e = this.abs(), i = t.t = 2 * e.t; --i >= 0;) t[i] = 0;
+ for (i = 0; i < e.t - 1; ++i) {
+ var r = e.am(i, e[i], t, 2 * i, 0, 1);
+ (t[i + e.t] += e.am(i + 1, 2 * e[i], t, 2 * i + 1, r, e.t - i - 1)) >= e.DV && (t[i + e.t] -= e.DV, t[i + e.t + 1] = 1)
+ }
+ t.t > 0 && (t[t.t - 1] += e.am(i, e[i], t, 2 * i, 0, 1)), t.s = 0, t.clamp()
+ }, t.prototype.divRemTo = function (e, i, r) {
+ var n = e.abs();
+ if (!(n.t <= 0)) {
+ var s = this.abs();
+ if (s.t < n.t) return null != i && i.fromInt(0), void (null != r && this.copyTo(r));
+ null == r && (r = N());
+ var o = N(), h = this.s, a = e.s, u = this.DB - F(n[n.t - 1]);
+ u > 0 ? (n.lShiftTo(u, o), s.lShiftTo(u, r)) : (n.copyTo(o), s.copyTo(r));
+ var c = o.t, f = o[c - 1];
+ if (0 != f) {
+ var l = f * (1 << this.F1) + (c > 1 ? o[c - 2] >> this.F2 : 0), p = this.FV / l,
+ g = (1 << this.F1) / l, d = 1 << this.F2, v = r.t, m = v - c,
+ y = null == i ? N() : i;
+ for (o.dlShiftTo(m, y), r.compareTo(y) >= 0 && (r[r.t++] = 1, r.subTo(y, r)), t.ONE.dlShiftTo(c, y), y.subTo(o, o); o.t < c;) o[o.t++] = 0;
+ for (; --m >= 0;) {
+ var b = r[--v] == f ? this.DM : Math.floor(r[v] * p + (r[v - 1] + d) * g);
+ if ((r[v] += o.am(0, b, r, m, 0, c)) < b) for (o.dlShiftTo(m, y), r.subTo(y, r); r[v] < --b;) r.subTo(y, r)
+ }
+ null != i && (r.drShiftTo(c, i), h != a && t.ZERO.subTo(i, i)), r.t = c, r.clamp(), u > 0 && r.rShiftTo(u, r), h < 0 && t.ZERO.subTo(r, r)
+ }
+ }
+ }, t.prototype.invDigit = function () {
+ if (this.t < 1) return 0;
+ var t = this[0];
+ if (0 == (1 & t)) return 0;
+ var e = 3 & t;
+ return (e = (e = (e = (e = e * (2 - (15 & t) * e) & 15) * (2 - (255 & t) * e) & 255) * (2 - ((65535 & t) * e & 65535)) & 65535) * (2 - t * e % this.DV) % this.DV) > 0 ? this.DV - e : -e
+ }, t.prototype.isEven = function () {
+ return 0 == (this.t > 0 ? 1 & this[0] : this.s)
+ }, t.prototype.exp = function (e, i) {
+ if (e > 4294967295 || e < 1) return t.ONE;
+ var r = N(), n = N(), s = i.convert(this), o = F(e) - 1;
+ for (s.copyTo(r); --o >= 0;) if (i.sqrTo(r, n), (e & 1 << o) > 0) i.mulTo(n, s, r); else {
+ var h = r;
+ r = n, n = h
+ }
+ return i.revert(r)
+ }, t.prototype.chunkSize = function (t) {
+ return Math.floor(Math.LN2 * this.DB / Math.log(t))
+ }, t.prototype.toRadix = function (t) {
+ if (null == t && (t = 10), 0 == this.signum() || t < 2 || t > 36) return "0";
+ var e = this.chunkSize(t), i = Math.pow(t, e), r = C(i), n = N(), s = N(), o = "";
+ for (this.divRemTo(r, n, s); n.signum() > 0;) o = (i + s.intValue()).toString(t).substr(1) + o, n.divRemTo(r, n, s);
+ return s.intValue().toString(t) + o
+ }, t.prototype.fromRadix = function (e, i) {
+ this.fromInt(0), null == i && (i = 10);
+ for (var r = this.chunkSize(i), n = Math.pow(i, r), s = !1, o = 0, h = 0, a = 0; a < e.length; ++a) {
+ var u = H(e, a);
+ u < 0 ? "-" == e.charAt(a) && 0 == this.signum() && (s = !0) : (h = i * h + u, ++o >= r && (this.dMultiply(n), this.dAddOffset(h, 0), o = 0, h = 0))
+ }
+ o > 0 && (this.dMultiply(Math.pow(i, o)), this.dAddOffset(h, 0)), s && t.ZERO.subTo(this, this)
+ }, t.prototype.fromNumber = function (e, i, r) {
+ if ("number" == typeof i) if (e < 2) this.fromInt(1); else for (this.fromNumber(e, r), this.testBit(e - 1) || this.bitwiseTo(t.ONE.shiftLeft(e - 1), s, this), this.isEven() && this.dAddOffset(1, 0); !this.isProbablePrime(i);) this.dAddOffset(2, 0), this.bitLength() > e && this.subTo(t.ONE.shiftLeft(e - 1), this); else {
+ var n = [], o = 7 & e;
+ n.length = 1 + (e >> 3), i.nextBytes(n), o > 0 ? n[0] &= (1 << o) - 1 : n[0] = 0, this.fromString(n, 256)
+ }
+ }, t.prototype.bitwiseTo = function (t, e, i) {
+ var r, n, s = Math.min(t.t, this.t);
+ for (r = 0; r < s; ++r) i[r] = e(this[r], t[r]);
+ if (t.t < this.t) {
+ for (n = t.s & this.DM, r = s; r < this.t; ++r) i[r] = e(this[r], n);
+ i.t = this.t
+ } else {
+ for (n = this.s & this.DM, r = s; r < t.t; ++r) i[r] = e(n, t[r]);
+ i.t = t.t
+ }
+ i.s = e(this.s, t.s), i.clamp()
+ }, t.prototype.changeBit = function (e, i) {
+ var r = t.ONE.shiftLeft(e);
+ return this.bitwiseTo(r, i, r), r
+ }, t.prototype.addTo = function (t, e) {
+ for (var i = 0, r = 0, n = Math.min(t.t, this.t); i < n;) r += this[i] + t[i], e[i++] = r & this.DM, r >>= this.DB;
+ if (t.t < this.t) {
+ for (r += t.s; i < this.t;) r += this[i], e[i++] = r & this.DM, r >>= this.DB;
+ r += this.s
+ } else {
+ for (r += this.s; i < t.t;) r += t[i], e[i++] = r & this.DM, r >>= this.DB;
+ r += t.s
+ }
+ e.s = r < 0 ? -1 : 0, r > 0 ? e[i++] = r : r < -1 && (e[i++] = this.DV + r), e.t = i, e.clamp()
+ }, t.prototype.dMultiply = function (t) {
+ this[this.t] = this.am(0, t - 1, this, 0, 0, this.t), ++this.t, this.clamp()
+ }, t.prototype.dAddOffset = function (t, e) {
+ if (0 != t) {
+ for (; this.t <= e;) this[this.t++] = 0;
+ for (this[e] += t; this[e] >= this.DV;) this[e] -= this.DV, ++e >= this.t && (this[this.t++] = 0), ++this[e]
+ }
+ }, t.prototype.multiplyLowerTo = function (t, e, i) {
+ var r = Math.min(this.t + t.t, e);
+ for (i.s = 0, i.t = r; r > 0;) i[--r] = 0;
+ for (var n = i.t - this.t; r < n; ++r) i[r + this.t] = this.am(0, t[r], i, r, 0, this.t);
+ for (n = Math.min(t.t, e); r < n; ++r) this.am(0, t[r], i, r, 0, e - r);
+ i.clamp()
+ }, t.prototype.multiplyUpperTo = function (t, e, i) {
+ --e;
+ var r = i.t = this.t + t.t - e;
+ for (i.s = 0; --r >= 0;) i[r] = 0;
+ for (r = Math.max(e - this.t, 0); r < t.t; ++r) i[this.t + r - e] = this.am(e - r, t[r], i, 0, 0, this.t + r - e);
+ i.clamp(), i.drShiftTo(1, i)
+ }, t.prototype.modInt = function (t) {
+ if (t <= 0) return 0;
+ var e = this.DV % t, i = this.s < 0 ? t - 1 : 0;
+ if (this.t > 0) if (0 == e) i = this[0] % t; else for (var r = this.t - 1; r >= 0; --r) i = (e * i + this[r]) % t;
+ return i
+ }, t.prototype.millerRabin = function (e) {
+ var i = this.subtract(t.ONE), r = i.getLowestSetBit();
+ if (r <= 0) return !1;
+ var n = i.shiftRight(r);
+ (e = e + 1 >> 1) > x.length && (e = x.length);
+ for (var s = N(), o = 0; o < e; ++o) {
+ s.fromInt(x[Math.floor(Math.random() * x.length)]);
+ var h = s.modPow(n, this);
+ if (0 != h.compareTo(t.ONE) && 0 != h.compareTo(i)) {
+ for (var a = 1; a++ < r && 0 != h.compareTo(i);) if (0 == (h = h.modPowInt(2, this)).compareTo(t.ONE)) return !1;
+ if (0 != h.compareTo(i)) return !1
+ }
+ }
+ return !0
+ }, t.prototype.square = function () {
+ var t = N();
+ return this.squareTo(t), t
+ }, t.prototype.gcda = function (t, e) {
+ var i = this.s < 0 ? this.negate() : this.clone(), r = t.s < 0 ? t.negate() : t.clone();
+ if (i.compareTo(r) < 0) {
+ var n = i;
+ i = r, r = n
+ }
+ var s = i.getLowestSetBit(), o = r.getLowestSetBit();
+ if (o < 0) e(i); else {
+ s < o && (o = s), o > 0 && (i.rShiftTo(o, i), r.rShiftTo(o, r));
+ var h = function () {
+ (s = i.getLowestSetBit()) > 0 && i.rShiftTo(s, i), (s = r.getLowestSetBit()) > 0 && r.rShiftTo(s, r), i.compareTo(r) >= 0 ? (i.subTo(r, i), i.rShiftTo(1, i)) : (r.subTo(i, r), r.rShiftTo(1, r)), i.signum() > 0 ? setTimeout(h, 0) : (o > 0 && r.lShiftTo(o, r), setTimeout((function () {
+ e(r)
+ }), 0))
+ };
+ setTimeout(h, 10)
+ }
+ }, t.prototype.fromNumberAsync = function (e, i, r, n) {
+ if ("number" == typeof i) if (e < 2) this.fromInt(1); else {
+ this.fromNumber(e, r), this.testBit(e - 1) || this.bitwiseTo(t.ONE.shiftLeft(e - 1), s, this), this.isEven() && this.dAddOffset(1, 0);
+ var o = this, h = function () {
+ o.dAddOffset(2, 0), o.bitLength() > e && o.subTo(t.ONE.shiftLeft(e - 1), o), o.isProbablePrime(i) ? setTimeout((function () {
+ n()
+ }), 0) : setTimeout(h, 0)
+ };
+ setTimeout(h, 0)
+ } else {
+ var a = [], u = 7 & e;
+ a.length = 1 + (e >> 3), i.nextBytes(a), u > 0 ? a[0] &= (1 << u) - 1 : a[0] = 0, this.fromString(a, 256)
+ }
+ }, t
+ }(), O = function () {
+ function t() {
+ }
+
+ return t.prototype.convert = function (t) {
+ return t
+ }, t.prototype.revert = function (t) {
+ return t
+ }, t.prototype.mulTo = function (t, e, i) {
+ t.multiplyTo(e, i)
+ }, t.prototype.sqrTo = function (t, e) {
+ t.squareTo(e)
+ }, t
+ }(), A = function () {
+ function t(t) {
+ this.m = t
+ }
+
+ return t.prototype.convert = function (t) {
+ return t.s < 0 || t.compareTo(this.m) >= 0 ? t.mod(this.m) : t
+ }, t.prototype.revert = function (t) {
+ return t
+ }, t.prototype.reduce = function (t) {
+ t.divRemTo(this.m, null, t)
+ }, t.prototype.mulTo = function (t, e, i) {
+ t.multiplyTo(e, i), this.reduce(i)
+ }, t.prototype.sqrTo = function (t, e) {
+ t.squareTo(e), this.reduce(e)
+ }, t
+ }(), V = function () {
+ function t(t) {
+ this.m = t, this.mp = t.invDigit(), this.mpl = 32767 & this.mp, this.mph = this.mp >> 15, this.um = (1 << t.DB - 15) - 1, this.mt2 = 2 * t.t
+ }
+
+ return t.prototype.convert = function (t) {
+ var e = N();
+ return t.abs().dlShiftTo(this.m.t, e), e.divRemTo(this.m, null, e), t.s < 0 && e.compareTo(B.ZERO) > 0 && this.m.subTo(e, e), e
+ }, t.prototype.revert = function (t) {
+ var e = N();
+ return t.copyTo(e), this.reduce(e), e
+ }, t.prototype.reduce = function (t) {
+ for (; t.t <= this.mt2;) t[t.t++] = 0;
+ for (var e = 0; e < this.m.t; ++e) {
+ var i = 32767 & t[e],
+ r = i * this.mpl + ((i * this.mph + (t[e] >> 15) * this.mpl & this.um) << 15) & t.DM;
+ for (t[i = e + this.m.t] += this.m.am(0, r, t, e, 0, this.m.t); t[i] >= t.DV;) t[i] -= t.DV, t[++i]++
+ }
+ t.clamp(), t.drShiftTo(this.m.t, t), t.compareTo(this.m) >= 0 && t.subTo(this.m, t)
+ }, t.prototype.mulTo = function (t, e, i) {
+ t.multiplyTo(e, i), this.reduce(i)
+ }, t.prototype.sqrTo = function (t, e) {
+ t.squareTo(e), this.reduce(e)
+ }, t
+ }(), I = function () {
+ function t(t) {
+ this.m = t, this.r2 = N(), this.q3 = N(), B.ONE.dlShiftTo(2 * t.t, this.r2), this.mu = this.r2.divide(t)
+ }
+
+ return t.prototype.convert = function (t) {
+ if (t.s < 0 || t.t > 2 * this.m.t) return t.mod(this.m);
+ if (t.compareTo(this.m) < 0) return t;
+ var e = N();
+ return t.copyTo(e), this.reduce(e), e
+ }, t.prototype.revert = function (t) {
+ return t
+ }, t.prototype.reduce = function (t) {
+ for (t.drShiftTo(this.m.t - 1, this.r2), t.t > this.m.t + 1 && (t.t = this.m.t + 1, t.clamp()), this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3), this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2); t.compareTo(this.r2) < 0;) t.dAddOffset(1, this.m.t + 1);
+ for (t.subTo(this.r2, t); t.compareTo(this.m) >= 0;) t.subTo(this.m, t)
+ }, t.prototype.mulTo = function (t, e, i) {
+ t.multiplyTo(e, i), this.reduce(i)
+ }, t.prototype.sqrTo = function (t, e) {
+ t.squareTo(e), this.reduce(e)
+ }, t
+ }();
+
+ function N() {
+ return new B(null)
+ }
+
+ function P(t, e) {
+ return new B(t, e)
+ }
+
+ var M = "undefined" != typeof navigator;
+ M && "Microsoft Internet Explorer" == navigator.appName ? (B.prototype.am = function (t, e, i, r, n, s) {
+ for (var o = 32767 & e, h = e >> 15; --s >= 0;) {
+ var a = 32767 & this[t], u = this[t++] >> 15, c = h * a + u * o;
+ n = ((a = o * a + ((32767 & c) << 15) + i[r] + (1073741823 & n)) >>> 30) + (c >>> 15) + h * u + (n >>> 30), i[r++] = 1073741823 & a
+ }
+ return n
+ }, S = 30) : M && "Netscape" != navigator.appName ? (B.prototype.am = function (t, e, i, r, n, s) {
+ for (; --s >= 0;) {
+ var o = e * this[t++] + i[r] + n;
+ n = Math.floor(o / 67108864), i[r++] = 67108863 & o
+ }
+ return n
+ }, S = 26) : (B.prototype.am = function (t, e, i, r, n, s) {
+ for (var o = 16383 & e, h = e >> 14; --s >= 0;) {
+ var a = 16383 & this[t], u = this[t++] >> 14, c = h * a + u * o;
+ n = ((a = o * a + ((16383 & c) << 14) + i[r] + n) >> 28) + (c >> 14) + h * u, i[r++] = 268435455 & a
+ }
+ return n
+ }, S = 28), B.prototype.DB = S, B.prototype.DM = (1 << S) - 1, B.prototype.DV = 1 << S, B.prototype.FV = Math.pow(2, 52), B.prototype.F1 = 52 - S, B.prototype.F2 = 2 * S - 52;
+ var j, q, L = [];
+ for (j = "0".charCodeAt(0), q = 0; q <= 9; ++q) L[j++] = q;
+ for (j = "a".charCodeAt(0), q = 10; q < 36; ++q) L[j++] = q;
+ for (j = "A".charCodeAt(0), q = 10; q < 36; ++q) L[j++] = q;
+
+ function H(t, e) {
+ var i = L[t.charCodeAt(e)];
+ return null == i ? -1 : i
+ }
+
+ function C(t) {
+ var e = N();
+ return e.fromInt(t), e
+ }
+
+ function F(t) {
+ var e, i = 1;
+ return 0 != (e = t >>> 16) && (t = e, i += 16), 0 != (e = t >> 8) && (t = e, i += 8), 0 != (e = t >> 4) && (t = e, i += 4), 0 != (e = t >> 2) && (t = e, i += 2), 0 != (e = t >> 1) && (t = e, i += 1), i
+ }
+
+ B.ZERO = C(0), B.ONE = C(1);
+ var U, K, k = function () {
+ function t() {
+ this.i = 0, this.j = 0, this.S = []
+ }
+
+ return t.prototype.init = function (t) {
+ var e, i, r;
+ for (e = 0; e < 256; ++e) this.S[e] = e;
+ for (i = 0, e = 0; e < 256; ++e) i = i + this.S[e] + t[e % t.length] & 255, r = this.S[e], this.S[e] = this.S[i], this.S[i] = r;
+ this.i = 0, this.j = 0
+ }, t.prototype.next = function () {
+ var t;
+ return this.i = this.i + 1 & 255, this.j = this.j + this.S[this.i] & 255, t = this.S[this.i], this.S[this.i] = this.S[this.j], this.S[this.j] = t, this.S[t + this.S[this.i] & 255]
+ }, t
+ }(), _ = null;
+ if (null == _) {
+ _ = [], K = 0;
+ var z = void 0;
+ if (window.crypto && window.crypto.getRandomValues) {
+ var Z = new Uint32Array(256);
+ for (window.crypto.getRandomValues(Z), z = 0; z < Z.length; ++z) _[K++] = 255 & Z[z]
+ }
+ var G = 0, $ = function (t) {
+ if ((G = G || 0) >= 256 || K >= 256) window.removeEventListener ? window.removeEventListener("mousemove", $, !1) : window.detachEvent && window.detachEvent("onmousemove", $); else try {
+ var e = t.x + t.y;
+ _[K++] = 255 & e, G += 1
+ } catch (t) {
+ }
+ };
+ window.addEventListener ? window.addEventListener("mousemove", $, !1) : window.attachEvent && window.attachEvent("onmousemove", $)
+ }
+
+ function Y() {
+ if (null == U) {
+ for (U = new k; K < 256;) {
+ var t = Math.floor(65536 * Math.random());
+ _[K++] = 255 & t
+ }
+ for (U.init(_), K = 0; K < _.length; ++K) _[K] = 0;
+ K = 0
+ }
+ return U.next()
+ }
+
+ var J = function () {
+ function t() {
+ }
+
+ return t.prototype.nextBytes = function (t) {
+ for (var e = 0; e < t.length; ++e) t[e] = Y()
+ }, t
+ }(), X = function () {
+ function t() {
+ this.n = null, this.e = 0, this.d = null, this.p = null, this.q = null, this.dmp1 = null, this.dmq1 = null, this.coeff = null
+ }
+
+ return t.prototype.doPublic = function (t) {
+ return t.modPowInt(this.e, this.n)
+ }, t.prototype.doPrivate = function (t) {
+ if (null == this.p || null == this.q) return t.modPow(this.d, this.n);
+ for (var e = t.mod(this.p).modPow(this.dmp1, this.p), i = t.mod(this.q).modPow(this.dmq1, this.q); e.compareTo(i) < 0;) e = e.add(this.p);
+ return e.subtract(i).multiply(this.coeff).mod(this.p).multiply(this.q).add(i)
+ }, t.prototype.setPublic = function (t, e) {
+ null != t && null != e && t.length > 0 && e.length > 0 ? (this.n = P(t, 16), this.e = parseInt(e, 16)) : console.error("Invalid RSA public key")
+ }, t.prototype.encrypt = function (t) {
+ var e = function (t, e) {
+ if (e < t.length + 11) return console.error("Message too long for RSA"), null;
+ for (var i = [], r = t.length - 1; r >= 0 && e > 0;) {
+ var n = t.charCodeAt(r--);
+ n < 128 ? i[--e] = n : n > 127 && n < 2048 ? (i[--e] = 63 & n | 128, i[--e] = n >> 6 | 192) : (i[--e] = 63 & n | 128, i[--e] = n >> 6 & 63 | 128, i[--e] = n >> 12 | 224)
+ }
+ i[--e] = 0;
+ for (var s = new J, o = []; e > 2;) {
+ for (o[0] = 0; 0 == o[0];) s.nextBytes(o);
+ i[--e] = o[0]
+ }
+ return i[--e] = 2, i[--e] = 0, new B(i)
+ }(t, this.n.bitLength() + 7 >> 3);
+ if (null == e) return null;
+ var i = this.doPublic(e);
+ if (null == i) return null;
+ var r = i.toString(16);
+ return 0 == (1 & r.length) ? r : "0" + r
+ }, t.prototype.setPrivate = function (t, e, i) {
+ null != t && null != e && t.length > 0 && e.length > 0 ? (this.n = P(t, 16), this.e = parseInt(e, 16), this.d = P(i, 16)) : console.error("Invalid RSA private key")
+ }, t.prototype.setPrivateEx = function (t, e, i, r, n, s, o, h) {
+ null != t && null != e && t.length > 0 && e.length > 0 ? (this.n = P(t, 16), this.e = parseInt(e, 16), this.d = P(i, 16), this.p = P(r, 16), this.q = P(n, 16), this.dmp1 = P(s, 16), this.dmq1 = P(o, 16), this.coeff = P(h, 16)) : console.error("Invalid RSA private key")
+ }, t.prototype.generate = function (t, e) {
+ var i = new J, r = t >> 1;
+ this.e = parseInt(e, 16);
+ for (var n = new B(e, 16); ;) {
+ for (; this.p = new B(t - r, 1, i), 0 != this.p.subtract(B.ONE).gcd(n).compareTo(B.ONE) || !this.p.isProbablePrime(10);) ;
+ for (; this.q = new B(r, 1, i), 0 != this.q.subtract(B.ONE).gcd(n).compareTo(B.ONE) || !this.q.isProbablePrime(10);) ;
+ if (this.p.compareTo(this.q) <= 0) {
+ var s = this.p;
+ this.p = this.q, this.q = s
+ }
+ var o = this.p.subtract(B.ONE), h = this.q.subtract(B.ONE), a = o.multiply(h);
+ if (0 == a.gcd(n).compareTo(B.ONE)) {
+ this.n = this.p.multiply(this.q), this.d = n.modInverse(a), this.dmp1 = this.d.mod(o), this.dmq1 = this.d.mod(h), this.coeff = this.q.modInverse(this.p);
+ break
+ }
+ }
+ }, t.prototype.decrypt = function (t) {
+ var e = P(t, 16), i = this.doPrivate(e);
+ return null == i ? null : function (t, e) {
+ for (var i = t.toByteArray(), r = 0; r < i.length && 0 == i[r];) ++r;
+ if (i.length - r != e - 1 || 2 != i[r]) return null;
+ for (++r; 0 != i[r];) if (++r >= i.length) return null;
+ for (var n = ""; ++r < i.length;) {
+ var s = 255 & i[r];
+ s < 128 ? n += String.fromCharCode(s) : s > 191 && s < 224 ? (n += String.fromCharCode((31 & s) << 6 | 63 & i[r + 1]), ++r) : (n += String.fromCharCode((15 & s) << 12 | (63 & i[r + 1]) << 6 | 63 & i[r + 2]), r += 2)
+ }
+ return n
+ }(i, this.n.bitLength() + 7 >> 3)
+ }, t.prototype.generateAsync = function (t, e, i) {
+ var r = new J, n = t >> 1;
+ this.e = parseInt(e, 16);
+ var s = new B(e, 16), o = this, h = function () {
+ var e = function () {
+ if (o.p.compareTo(o.q) <= 0) {
+ var t = o.p;
+ o.p = o.q, o.q = t
+ }
+ var e = o.p.subtract(B.ONE), r = o.q.subtract(B.ONE), n = e.multiply(r);
+ 0 == n.gcd(s).compareTo(B.ONE) ? (o.n = o.p.multiply(o.q), o.d = s.modInverse(n), o.dmp1 = o.d.mod(e), o.dmq1 = o.d.mod(r), o.coeff = o.q.modInverse(o.p), setTimeout((function () {
+ i()
+ }), 0)) : setTimeout(h, 0)
+ }, a = function () {
+ o.q = N(), o.q.fromNumberAsync(n, 1, r, (function () {
+ o.q.subtract(B.ONE).gcda(s, (function (t) {
+ 0 == t.compareTo(B.ONE) && o.q.isProbablePrime(10) ? setTimeout(e, 0) : setTimeout(a, 0)
+ }))
+ }))
+ }, u = function () {
+ o.p = N(), o.p.fromNumberAsync(t - n, 1, r, (function () {
+ o.p.subtract(B.ONE).gcda(s, (function (t) {
+ 0 == t.compareTo(B.ONE) && o.p.isProbablePrime(10) ? setTimeout(a, 0) : setTimeout(u, 0)
+ }))
+ }))
+ };
+ setTimeout(u, 0)
+ };
+ setTimeout(h, 0)
+ }, t.prototype.sign = function (t, e, i) {
+ var r = function (t, e) {
+ if (e < t.length + 22) return console.error("Message too long for RSA"), null;
+ for (var i = e - t.length - 6, r = "", n = 0; n < i; n += 2) r += "ff";
+ return P("0001" + r + "00" + t, 16)
+ }((Q[i] || "") + e(t).toString(), this.n.bitLength() / 4);
+ if (null == r) return null;
+ var n = this.doPrivate(r);
+ if (null == n) return null;
+ var s = n.toString(16);
+ return 0 == (1 & s.length) ? s : "0" + s
+ }, t.prototype.verify = function (t, e, i) {
+ var r = P(e, 16), n = this.doPublic(r);
+ return null == n ? null : function (t) {
+ for (var e in Q) if (Q.hasOwnProperty(e)) {
+ var i = Q[e], r = i.length;
+ if (t.substr(0, r) == i) return t.substr(r)
+ }
+ return t
+ }(n.toString(16).replace(/^1f+00/, "")) == i(t).toString()
+ }, t
+ }(), Q = {
+ md2: "3020300c06082a864886f70d020205000410",
+ md5: "3020300c06082a864886f70d020505000410",
+ sha1: "3021300906052b0e03021a05000414",
+ sha224: "302d300d06096086480165030402040500041c",
+ sha256: "3031300d060960864801650304020105000420",
+ sha384: "3041300d060960864801650304020205000430",
+ sha512: "3051300d060960864801650304020305000440",
+ ripemd160: "3021300906052b2403020105000414"
+ }, W = {};
+ W.lang = {
+ extend: function (t, e, i) {
+ if (!e || !t) throw new Error("YAHOO.lang.extend failed, please check that all dependencies are included.");
+ var r = function () {
+ };
+ if (r.prototype = e.prototype, t.prototype = new r, t.prototype.constructor = t, t.superclass = e.prototype, e.prototype.constructor == Object.prototype.constructor && (e.prototype.constructor = e), i) {
+ var n;
+ for (n in i) t.prototype[n] = i[n];
+ var s = function () {
+ }, o = ["toString", "valueOf"];
+ try {
+ /MSIE/.test(navigator.userAgent) && (s = function (t, e) {
+ for (n = 0; n < o.length; n += 1) {
+ var i = o[n], r = e[i];
+ "function" == typeof r && r != Object.prototype[i] && (t[i] = r)
+ }
+ })
+ } catch (t) {
+ }
+ s(t.prototype, i)
+ }
+ }
+ };
+ var tt = {};
+ void 0 !== tt.asn1 && tt.asn1 || (tt.asn1 = {}), tt.asn1.ASN1Util = new function () {
+ this.integerToByteHex = function (t) {
+ var e = t.toString(16);
+ return e.length % 2 == 1 && (e = "0" + e), e
+ }, this.bigIntToMinTwosComplementsHex = function (t) {
+ var e = t.toString(16);
+ if ("-" != e.substr(0, 1)) e.length % 2 == 1 ? e = "0" + e : e.match(/^[0-7]/) || (e = "00" + e); else {
+ var i = e.substr(1).length;
+ i % 2 == 1 ? i += 1 : e.match(/^[0-7]/) || (i += 2);
+ for (var r = "", n = 0; n < i; n++) r += "f";
+ e = new B(r, 16).xor(t).add(B.ONE).toString(16).replace(/^-/, "")
+ }
+ return e
+ }, this.getPEMStringFromHex = function (t, e) {
+ return hextopem(t, e)
+ }, this.newObject = function (t) {
+ var e = tt.asn1, i = e.DERBoolean, r = e.DERInteger, n = e.DERBitString, s = e.DEROctetString,
+ o = e.DERNull, h = e.DERObjectIdentifier, a = e.DEREnumerated, u = e.DERUTF8String,
+ c = e.DERNumericString, f = e.DERPrintableString, l = e.DERTeletexString,
+ p = e.DERIA5String, g = e.DERUTCTime, d = e.DERGeneralizedTime, v = e.DERSequence,
+ m = e.DERSet, y = e.DERTaggedObject, b = e.ASN1Util.newObject, T = Object.keys(t);
+ if (1 != T.length) throw"key of param shall be only one.";
+ var S = T[0];
+ if (-1 == ":bool:int:bitstr:octstr:null:oid:enum:utf8str:numstr:prnstr:telstr:ia5str:utctime:gentime:seq:set:tag:".indexOf(":" + S + ":")) throw"undefined key: " + S;
+ if ("bool" == S) return new i(t[S]);
+ if ("int" == S) return new r(t[S]);
+ if ("bitstr" == S) return new n(t[S]);
+ if ("octstr" == S) return new s(t[S]);
+ if ("null" == S) return new o(t[S]);
+ if ("oid" == S) return new h(t[S]);
+ if ("enum" == S) return new a(t[S]);
+ if ("utf8str" == S) return new u(t[S]);
+ if ("numstr" == S) return new c(t[S]);
+ if ("prnstr" == S) return new f(t[S]);
+ if ("telstr" == S) return new l(t[S]);
+ if ("ia5str" == S) return new p(t[S]);
+ if ("utctime" == S) return new g(t[S]);
+ if ("gentime" == S) return new d(t[S]);
+ if ("seq" == S) {
+ for (var E = t[S], w = [], D = 0; D < E.length; D++) {
+ var x = b(E[D]);
+ w.push(x)
+ }
+ return new v({array: w})
+ }
+ if ("set" == S) {
+ for (E = t[S], w = [], D = 0; D < E.length; D++) x = b(E[D]), w.push(x);
+ return new m({array: w})
+ }
+ if ("tag" == S) {
+ var R = t[S];
+ if ("[object Array]" === Object.prototype.toString.call(R) && 3 == R.length) {
+ var B = b(R[2]);
+ return new y({tag: R[0], explicit: R[1], obj: B})
+ }
+ var O = {};
+ if (void 0 !== R.explicit && (O.explicit = R.explicit), void 0 !== R.tag && (O.tag = R.tag), void 0 === R.obj) throw"obj shall be specified for 'tag'.";
+ return O.obj = b(R.obj), new y(O)
+ }
+ }, this.jsonToASN1HEX = function (t) {
+ return this.newObject(t).getEncodedHex()
+ }
+ }, tt.asn1.ASN1Util.oidHexToInt = function (t) {
+ for (var e = "", i = parseInt(t.substr(0, 2), 16), r = (e = Math.floor(i / 40) + "." + i % 40, ""), n = 2; n < t.length; n += 2) {
+ var s = ("00000000" + parseInt(t.substr(n, 2), 16).toString(2)).slice(-8);
+ r += s.substr(1, 7), "0" == s.substr(0, 1) && (e = e + "." + new B(r, 2).toString(10), r = "")
+ }
+ return e
+ }, tt.asn1.ASN1Util.oidIntToHex = function (t) {
+ var e = function (t) {
+ var e = t.toString(16);
+ return 1 == e.length && (e = "0" + e), e
+ }, i = function (t) {
+ var i = "", r = new B(t, 10).toString(2), n = 7 - r.length % 7;
+ 7 == n && (n = 0);
+ for (var s = "", o = 0; o < n; o++) s += "0";
+ for (r = s + r, o = 0; o < r.length - 1; o += 7) {
+ var h = r.substr(o, 7);
+ o != r.length - 7 && (h = "1" + h), i += e(parseInt(h, 2))
+ }
+ return i
+ };
+ if (!t.match(/^[0-9.]+$/)) throw"malformed oid string: " + t;
+ var r = "", n = t.split("."), s = 40 * parseInt(n[0]) + parseInt(n[1]);
+ r += e(s), n.splice(0, 2);
+ for (var o = 0; o < n.length; o++) r += i(n[o]);
+ return r
+ }, tt.asn1.ASN1Object = function () {
+ this.getLengthHexFromValue = function () {
+ if (void 0 === this.hV || null == this.hV) throw"this.hV is null or undefined.";
+ if (this.hV.length % 2 == 1) throw"value hex must be even length: n=" + "".length + ",v=" + this.hV;
+ var t = this.hV.length / 2, e = t.toString(16);
+ if (e.length % 2 == 1 && (e = "0" + e), t < 128) return e;
+ var i = e.length / 2;
+ if (i > 15) throw"ASN.1 length too long to represent by 8x: n = " + t.toString(16);
+ return (128 + i).toString(16) + e
+ }, this.getEncodedHex = function () {
+ return (null == this.hTLV || this.isModified) && (this.hV = this.getFreshValueHex(), this.hL = this.getLengthHexFromValue(), this.hTLV = this.hT + this.hL + this.hV, this.isModified = !1), this.hTLV
+ }, this.getValueHex = function () {
+ return this.getEncodedHex(), this.hV
+ }, this.getFreshValueHex = function () {
+ return ""
+ }
+ }, tt.asn1.DERAbstractString = function (t) {
+ tt.asn1.DERAbstractString.superclass.constructor.call(this), this.getString = function () {
+ return this.s
+ }, this.setString = function (t) {
+ this.hTLV = null, this.isModified = !0, this.s = t, this.hV = stohex(this.s)
+ }, this.setStringHex = function (t) {
+ this.hTLV = null, this.isModified = !0, this.s = null, this.hV = t
+ }, this.getFreshValueHex = function () {
+ return this.hV
+ }, void 0 !== t && ("string" == typeof t ? this.setString(t) : void 0 !== t.str ? this.setString(t.str) : void 0 !== t.hex && this.setStringHex(t.hex))
+ }, W.lang.extend(tt.asn1.DERAbstractString, tt.asn1.ASN1Object), tt.asn1.DERAbstractTime = function (t) {
+ tt.asn1.DERAbstractTime.superclass.constructor.call(this), this.localDateToUTC = function (t) {
+ return utc = t.getTime() + 6e4 * t.getTimezoneOffset(), new Date(utc)
+ }, this.formatDate = function (t, e, i) {
+ var r = this.zeroPadding, n = this.localDateToUTC(t), s = String(n.getFullYear());
+ "utc" == e && (s = s.substr(2, 2));
+ var o = s + r(String(n.getMonth() + 1), 2) + r(String(n.getDate()), 2) + r(String(n.getHours()), 2) + r(String(n.getMinutes()), 2) + r(String(n.getSeconds()), 2);
+ if (!0 === i) {
+ var h = n.getMilliseconds();
+ if (0 != h) {
+ var a = r(String(h), 3);
+ o = o + "." + (a = a.replace(/[0]+$/, ""))
+ }
+ }
+ return o + "Z"
+ }, this.zeroPadding = function (t, e) {
+ return t.length >= e ? t : new Array(e - t.length + 1).join("0") + t
+ }, this.getString = function () {
+ return this.s
+ }, this.setString = function (t) {
+ this.hTLV = null, this.isModified = !0, this.s = t, this.hV = stohex(t)
+ }, this.setByDateValue = function (t, e, i, r, n, s) {
+ var o = new Date(Date.UTC(t, e - 1, i, r, n, s, 0));
+ this.setByDate(o)
+ }, this.getFreshValueHex = function () {
+ return this.hV
+ }
+ }, W.lang.extend(tt.asn1.DERAbstractTime, tt.asn1.ASN1Object), tt.asn1.DERAbstractStructured = function (t) {
+ tt.asn1.DERAbstractString.superclass.constructor.call(this), this.setByASN1ObjectArray = function (t) {
+ this.hTLV = null, this.isModified = !0, this.asn1Array = t
+ }, this.appendASN1Object = function (t) {
+ this.hTLV = null, this.isModified = !0, this.asn1Array.push(t)
+ }, this.asn1Array = new Array, void 0 !== t && void 0 !== t.array && (this.asn1Array = t.array)
+ }, W.lang.extend(tt.asn1.DERAbstractStructured, tt.asn1.ASN1Object), tt.asn1.DERBoolean = function () {
+ tt.asn1.DERBoolean.superclass.constructor.call(this), this.hT = "01", this.hTLV = "0101ff"
+ }, W.lang.extend(tt.asn1.DERBoolean, tt.asn1.ASN1Object), tt.asn1.DERInteger = function (t) {
+ tt.asn1.DERInteger.superclass.constructor.call(this), this.hT = "02", this.setByBigInteger = function (t) {
+ this.hTLV = null, this.isModified = !0, this.hV = tt.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)
+ }, this.setByInteger = function (t) {
+ var e = new B(String(t), 10);
+ this.setByBigInteger(e)
+ }, this.setValueHex = function (t) {
+ this.hV = t
+ }, this.getFreshValueHex = function () {
+ return this.hV
+ }, void 0 !== t && (void 0 !== t.bigint ? this.setByBigInteger(t.bigint) : void 0 !== t.int ? this.setByInteger(t.int) : "number" == typeof t ? this.setByInteger(t) : void 0 !== t.hex && this.setValueHex(t.hex))
+ }, W.lang.extend(tt.asn1.DERInteger, tt.asn1.ASN1Object), tt.asn1.DERBitString = function (t) {
+ if (void 0 !== t && void 0 !== t.obj) {
+ var e = tt.asn1.ASN1Util.newObject(t.obj);
+ t.hex = "00" + e.getEncodedHex()
+ }
+ tt.asn1.DERBitString.superclass.constructor.call(this), this.hT = "03", this.setHexValueIncludingUnusedBits = function (t) {
+ this.hTLV = null, this.isModified = !0, this.hV = t
+ }, this.setUnusedBitsAndHexValue = function (t, e) {
+ if (t < 0 || 7 < t) throw"unused bits shall be from 0 to 7: u = " + t;
+ var i = "0" + t;
+ this.hTLV = null, this.isModified = !0, this.hV = i + e
+ }, this.setByBinaryString = function (t) {
+ var e = 8 - (t = t.replace(/0+$/, "")).length % 8;
+ 8 == e && (e = 0);
+ for (var i = 0; i <= e; i++) t += "0";
+ var r = "";
+ for (i = 0; i < t.length - 1; i += 8) {
+ var n = t.substr(i, 8), s = parseInt(n, 2).toString(16);
+ 1 == s.length && (s = "0" + s), r += s
+ }
+ this.hTLV = null, this.isModified = !0, this.hV = "0" + e + r
+ }, this.setByBooleanArray = function (t) {
+ for (var e = "", i = 0; i < t.length; i++) 1 == t[i] ? e += "1" : e += "0";
+ this.setByBinaryString(e)
+ }, this.newFalseArray = function (t) {
+ for (var e = new Array(t), i = 0; i < t; i++) e[i] = !1;
+ return e
+ }, this.getFreshValueHex = function () {
+ return this.hV
+ }, void 0 !== t && ("string" == typeof t && t.toLowerCase().match(/^[0-9a-f]+$/) ? this.setHexValueIncludingUnusedBits(t) : void 0 !== t.hex ? this.setHexValueIncludingUnusedBits(t.hex) : void 0 !== t.bin ? this.setByBinaryString(t.bin) : void 0 !== t.array && this.setByBooleanArray(t.array))
+ }, W.lang.extend(tt.asn1.DERBitString, tt.asn1.ASN1Object), tt.asn1.DEROctetString = function (t) {
+ if (void 0 !== t && void 0 !== t.obj) {
+ var e = tt.asn1.ASN1Util.newObject(t.obj);
+ t.hex = e.getEncodedHex()
+ }
+ tt.asn1.DEROctetString.superclass.constructor.call(this, t), this.hT = "04"
+ }, W.lang.extend(tt.asn1.DEROctetString, tt.asn1.DERAbstractString), tt.asn1.DERNull = function () {
+ tt.asn1.DERNull.superclass.constructor.call(this), this.hT = "05", this.hTLV = "0500"
+ }, W.lang.extend(tt.asn1.DERNull, tt.asn1.ASN1Object), tt.asn1.DERObjectIdentifier = function (t) {
+ var e = function (t) {
+ var e = t.toString(16);
+ return 1 == e.length && (e = "0" + e), e
+ }, i = function (t) {
+ var i = "", r = new B(t, 10).toString(2), n = 7 - r.length % 7;
+ 7 == n && (n = 0);
+ for (var s = "", o = 0; o < n; o++) s += "0";
+ for (r = s + r, o = 0; o < r.length - 1; o += 7) {
+ var h = r.substr(o, 7);
+ o != r.length - 7 && (h = "1" + h), i += e(parseInt(h, 2))
+ }
+ return i
+ };
+ tt.asn1.DERObjectIdentifier.superclass.constructor.call(this), this.hT = "06", this.setValueHex = function (t) {
+ this.hTLV = null, this.isModified = !0, this.s = null, this.hV = t
+ }, this.setValueOidString = function (t) {
+ if (!t.match(/^[0-9.]+$/)) throw"malformed oid string: " + t;
+ var r = "", n = t.split("."), s = 40 * parseInt(n[0]) + parseInt(n[1]);
+ r += e(s), n.splice(0, 2);
+ for (var o = 0; o < n.length; o++) r += i(n[o]);
+ this.hTLV = null, this.isModified = !0, this.s = null, this.hV = r
+ }, this.setValueName = function (t) {
+ var e = tt.asn1.x509.OID.name2oid(t);
+ if ("" === e) throw"DERObjectIdentifier oidName undefined: " + t;
+ this.setValueOidString(e)
+ }, this.getFreshValueHex = function () {
+ return this.hV
+ }, void 0 !== t && ("string" == typeof t ? t.match(/^[0-2].[0-9.]+$/) ? this.setValueOidString(t) : this.setValueName(t) : void 0 !== t.oid ? this.setValueOidString(t.oid) : void 0 !== t.hex ? this.setValueHex(t.hex) : void 0 !== t.name && this.setValueName(t.name))
+ }, W.lang.extend(tt.asn1.DERObjectIdentifier, tt.asn1.ASN1Object), tt.asn1.DEREnumerated = function (t) {
+ tt.asn1.DEREnumerated.superclass.constructor.call(this), this.hT = "0a", this.setByBigInteger = function (t) {
+ this.hTLV = null, this.isModified = !0, this.hV = tt.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)
+ }, this.setByInteger = function (t) {
+ var e = new B(String(t), 10);
+ this.setByBigInteger(e)
+ }, this.setValueHex = function (t) {
+ this.hV = t
+ }, this.getFreshValueHex = function () {
+ return this.hV
+ }, void 0 !== t && (void 0 !== t.int ? this.setByInteger(t.int) : "number" == typeof t ? this.setByInteger(t) : void 0 !== t.hex && this.setValueHex(t.hex))
+ }, W.lang.extend(tt.asn1.DEREnumerated, tt.asn1.ASN1Object), tt.asn1.DERUTF8String = function (t) {
+ tt.asn1.DERUTF8String.superclass.constructor.call(this, t), this.hT = "0c"
+ }, W.lang.extend(tt.asn1.DERUTF8String, tt.asn1.DERAbstractString), tt.asn1.DERNumericString = function (t) {
+ tt.asn1.DERNumericString.superclass.constructor.call(this, t), this.hT = "12"
+ }, W.lang.extend(tt.asn1.DERNumericString, tt.asn1.DERAbstractString), tt.asn1.DERPrintableString = function (t) {
+ tt.asn1.DERPrintableString.superclass.constructor.call(this, t), this.hT = "13"
+ }, W.lang.extend(tt.asn1.DERPrintableString, tt.asn1.DERAbstractString), tt.asn1.DERTeletexString = function (t) {
+ tt.asn1.DERTeletexString.superclass.constructor.call(this, t), this.hT = "14"
+ }, W.lang.extend(tt.asn1.DERTeletexString, tt.asn1.DERAbstractString), tt.asn1.DERIA5String = function (t) {
+ tt.asn1.DERIA5String.superclass.constructor.call(this, t), this.hT = "16"
+ }, W.lang.extend(tt.asn1.DERIA5String, tt.asn1.DERAbstractString), tt.asn1.DERUTCTime = function (t) {
+ tt.asn1.DERUTCTime.superclass.constructor.call(this, t), this.hT = "17", this.setByDate = function (t) {
+ this.hTLV = null, this.isModified = !0, this.date = t, this.s = this.formatDate(this.date, "utc"), this.hV = stohex(this.s)
+ }, this.getFreshValueHex = function () {
+ return void 0 === this.date && void 0 === this.s && (this.date = new Date, this.s = this.formatDate(this.date, "utc"), this.hV = stohex(this.s)), this.hV
+ }, void 0 !== t && (void 0 !== t.str ? this.setString(t.str) : "string" == typeof t && t.match(/^[0-9]{12}Z$/) ? this.setString(t) : void 0 !== t.hex ? this.setStringHex(t.hex) : void 0 !== t.date && this.setByDate(t.date))
+ }, W.lang.extend(tt.asn1.DERUTCTime, tt.asn1.DERAbstractTime), tt.asn1.DERGeneralizedTime = function (t) {
+ tt.asn1.DERGeneralizedTime.superclass.constructor.call(this, t), this.hT = "18", this.withMillis = !1, this.setByDate = function (t) {
+ this.hTLV = null, this.isModified = !0, this.date = t, this.s = this.formatDate(this.date, "gen", this.withMillis), this.hV = stohex(this.s)
+ }, this.getFreshValueHex = function () {
+ return void 0 === this.date && void 0 === this.s && (this.date = new Date, this.s = this.formatDate(this.date, "gen", this.withMillis), this.hV = stohex(this.s)), this.hV
+ }, void 0 !== t && (void 0 !== t.str ? this.setString(t.str) : "string" == typeof t && t.match(/^[0-9]{14}Z$/) ? this.setString(t) : void 0 !== t.hex ? this.setStringHex(t.hex) : void 0 !== t.date && this.setByDate(t.date), !0 === t.millis && (this.withMillis = !0))
+ }, W.lang.extend(tt.asn1.DERGeneralizedTime, tt.asn1.DERAbstractTime), tt.asn1.DERSequence = function (t) {
+ tt.asn1.DERSequence.superclass.constructor.call(this, t), this.hT = "30", this.getFreshValueHex = function () {
+ for (var t = "", e = 0; e < this.asn1Array.length; e++) t += this.asn1Array[e].getEncodedHex();
+ return this.hV = t, this.hV
+ }
+ }, W.lang.extend(tt.asn1.DERSequence, tt.asn1.DERAbstractStructured), tt.asn1.DERSet = function (t) {
+ tt.asn1.DERSet.superclass.constructor.call(this, t), this.hT = "31", this.sortFlag = !0, this.getFreshValueHex = function () {
+ for (var t = new Array, e = 0; e < this.asn1Array.length; e++) {
+ var i = this.asn1Array[e];
+ t.push(i.getEncodedHex())
+ }
+ return 1 == this.sortFlag && t.sort(), this.hV = t.join(""), this.hV
+ }, void 0 !== t && void 0 !== t.sortflag && 0 == t.sortflag && (this.sortFlag = !1)
+ }, W.lang.extend(tt.asn1.DERSet, tt.asn1.DERAbstractStructured), tt.asn1.DERTaggedObject = function (t) {
+ tt.asn1.DERTaggedObject.superclass.constructor.call(this), this.hT = "a0", this.hV = "", this.isExplicit = !0, this.asn1Object = null, this.setASN1Object = function (t, e, i) {
+ this.hT = e, this.isExplicit = t, this.asn1Object = i, this.isExplicit ? (this.hV = this.asn1Object.getEncodedHex(), this.hTLV = null, this.isModified = !0) : (this.hV = null, this.hTLV = i.getEncodedHex(), this.hTLV = this.hTLV.replace(/^../, e), this.isModified = !1)
+ }, this.getFreshValueHex = function () {
+ return this.hV
+ }, void 0 !== t && (void 0 !== t.tag && (this.hT = t.tag), void 0 !== t.explicit && (this.isExplicit = t.explicit), void 0 !== t.obj && (this.asn1Object = t.obj, this.setASN1Object(this.isExplicit, this.hT, this.asn1Object)))
+ }, W.lang.extend(tt.asn1.DERTaggedObject, tt.asn1.ASN1Object);
+ var et, it = (et = function (t, e) {
+ return (et = Object.setPrototypeOf || {__proto__: []} instanceof Array && function (t, e) {
+ t.__proto__ = e
+ } || function (t, e) {
+ for (var i in e) Object.prototype.hasOwnProperty.call(e, i) && (t[i] = e[i])
+ })(t, e)
+ }, function (t, e) {
+ function i() {
+ this.constructor = t
+ }
+
+ et(t, e), t.prototype = null === e ? Object.create(e) : (i.prototype = e.prototype, new i)
+ }), rt = function (t) {
+ function e(i) {
+ var r = t.call(this) || this;
+ return i && ("string" == typeof i ? r.parseKey(i) : (e.hasPrivateKeyProperty(i) || e.hasPublicKeyProperty(i)) && r.parsePropertiesFrom(i)), r
+ }
+
+ return it(e, t), e.prototype.parseKey = function (t) {
+ try {
+ var e = 0, i = 0, r = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/.test(t) ? function (t) {
+ var e;
+ if (void 0 === c) {
+ var i = "0123456789ABCDEF", r = " \f\n\r\t \u2028\u2029";
+ for (c = {}, e = 0; e < 16; ++e) c[i.charAt(e)] = e;
+ for (i = i.toLowerCase(), e = 10; e < 16; ++e) c[i.charAt(e)] = e;
+ for (e = 0; e < r.length; ++e) c[r.charAt(e)] = -1
+ }
+ var n = [], s = 0, o = 0;
+ for (e = 0; e < t.length; ++e) {
+ var h = t.charAt(e);
+ if ("=" == h) break;
+ if (-1 != (h = c[h])) {
+ if (void 0 === h) throw new Error("Illegal character at offset " + e);
+ s |= h, ++o >= 2 ? (n[n.length] = s, s = 0, o = 0) : s <<= 4
+ }
+ }
+ if (o) throw new Error("Hex encoding incomplete: 4 bits missing");
+ return n
+ }(t) : d.unarmor(t), n = w.decode(r);
+ if (3 === n.sub.length && (n = n.sub[2].sub[0]), 9 === n.sub.length) {
+ e = n.sub[1].getHexStringValue(), this.n = P(e, 16), i = n.sub[2].getHexStringValue(), this.e = parseInt(i, 16);
+ var s = n.sub[3].getHexStringValue();
+ this.d = P(s, 16);
+ var o = n.sub[4].getHexStringValue();
+ this.p = P(o, 16);
+ var h = n.sub[5].getHexStringValue();
+ this.q = P(h, 16);
+ var a = n.sub[6].getHexStringValue();
+ this.dmp1 = P(a, 16);
+ var u = n.sub[7].getHexStringValue();
+ this.dmq1 = P(u, 16);
+ var f = n.sub[8].getHexStringValue();
+ this.coeff = P(f, 16)
+ } else {
+ if (2 !== n.sub.length) return !1;
+ var l = n.sub[1].sub[0];
+ e = l.sub[0].getHexStringValue(), this.n = P(e, 16), i = l.sub[1].getHexStringValue(), this.e = parseInt(i, 16)
+ }
+ return !0
+ } catch (t) {
+ return !1
+ }
+ }, e.prototype.getPrivateBaseKey = function () {
+ var t = {array: [new tt.asn1.DERInteger({int: 0}), new tt.asn1.DERInteger({bigint: this.n}), new tt.asn1.DERInteger({int: this.e}), new tt.asn1.DERInteger({bigint: this.d}), new tt.asn1.DERInteger({bigint: this.p}), new tt.asn1.DERInteger({bigint: this.q}), new tt.asn1.DERInteger({bigint: this.dmp1}), new tt.asn1.DERInteger({bigint: this.dmq1}), new tt.asn1.DERInteger({bigint: this.coeff})]};
+ return new tt.asn1.DERSequence(t).getEncodedHex()
+ }, e.prototype.getPrivateBaseKeyB64 = function () {
+ return l(this.getPrivateBaseKey())
+ }, e.prototype.getPublicBaseKey = function () {
+ var t = new tt.asn1.DERSequence({array: [new tt.asn1.DERObjectIdentifier({oid: "1.2.840.113549.1.1.1"}), new tt.asn1.DERNull]}),
+ e = new tt.asn1.DERSequence({array: [new tt.asn1.DERInteger({bigint: this.n}), new tt.asn1.DERInteger({int: this.e})]}),
+ i = new tt.asn1.DERBitString({hex: "00" + e.getEncodedHex()});
+ return new tt.asn1.DERSequence({array: [t, i]}).getEncodedHex()
+ }, e.prototype.getPublicBaseKeyB64 = function () {
+ return l(this.getPublicBaseKey())
+ }, e.wordwrap = function (t, e) {
+ if (!t) return t;
+ var i = "(.{1," + (e = e || 64) + "})( +|$\n?)|(.{1," + e + "})";
+ return t.match(RegExp(i, "g")).join("\n")
+ }, e.prototype.getPrivateKey = function () {
+ var t = "-----BEGIN RSA PRIVATE KEY-----\n";
+ return (t += e.wordwrap(this.getPrivateBaseKeyB64()) + "\n") + "-----END RSA PRIVATE KEY-----"
+ }, e.prototype.getPublicKey = function () {
+ var t = "-----BEGIN PUBLIC KEY-----\n";
+ return (t += e.wordwrap(this.getPublicBaseKeyB64()) + "\n") + "-----END PUBLIC KEY-----"
+ }, e.hasPublicKeyProperty = function (t) {
+ return (t = t || {}).hasOwnProperty("n") && t.hasOwnProperty("e")
+ }, e.hasPrivateKeyProperty = function (t) {
+ return (t = t || {}).hasOwnProperty("n") && t.hasOwnProperty("e") && t.hasOwnProperty("d") && t.hasOwnProperty("p") && t.hasOwnProperty("q") && t.hasOwnProperty("dmp1") && t.hasOwnProperty("dmq1") && t.hasOwnProperty("coeff")
+ }, e.prototype.parsePropertiesFrom = function (t) {
+ this.n = t.n, this.e = t.e, t.hasOwnProperty("d") && (this.d = t.d, this.p = t.p, this.q = t.q, this.dmp1 = t.dmp1, this.dmq1 = t.dmq1, this.coeff = t.coeff)
+ }, e
+ }(X);
+ const nt = function () {
+ function t(t) {
+ t = t || {}, this.default_key_size = t.default_key_size ? parseInt(t.default_key_size, 10) : 1024, this.default_public_exponent = t.default_public_exponent || "010001", this.log = t.log || !1, this.key = null
+ }
+
+ return t.prototype.setKey = function (t) {
+ this.log && this.key && console.warn("A key was already set, overriding existing."), this.key = new rt(t)
+ }, t.prototype.setPrivateKey = function (t) {
+ this.setKey(t)
+ }, t.prototype.setPublicKey = function (t) {
+ this.setKey(t)
+ }, t.prototype.decrypt = function (t) {
+ try {
+ return this.getKey().decrypt(p(t))
+ } catch (t) {
+ return !1
+ }
+ }, t.prototype.encrypt = function (t) {
+ try {
+ return l(this.getKey().encrypt(t))
+ } catch (t) {
+ return !1
+ }
+ }, t.prototype.sign = function (t, e, i) {
+ try {
+ return l(this.getKey().sign(t, e, i))
+ } catch (t) {
+ return !1
+ }
+ }, t.prototype.verify = function (t, e, i) {
+ try {
+ return this.getKey().verify(t, p(e), i)
+ } catch (t) {
+ return !1
+ }
+ }, t.prototype.getKey = function (t) {
+ if (!this.key) {
+ if (this.key = new rt, t && "[object Function]" === {}.toString.call(t)) return void this.key.generateAsync(this.default_key_size, this.default_public_exponent, t);
+ this.key.generate(this.default_key_size, this.default_public_exponent)
+ }
+ return this.key
+ }, t.prototype.getPrivateKey = function () {
+ return this.getKey().getPrivateKey()
+ }, t.prototype.getPrivateKeyB64 = function () {
+ return this.getKey().getPrivateBaseKeyB64()
+ }, t.prototype.getPublicKey = function () {
+ return this.getKey().getPublicKey()
+ }, t.prototype.getPublicKeyB64 = function () {
+ return this.getKey().getPublicBaseKeyB64()
+ }, t.version = "3.0.0-rc.2", t
+ }()
+ }
+ }, e = {};
+
+ function i(r) {
+ if (e[r]) return e[r].exports;
+ var n = e[r] = {exports: {}};
+ return t[r](n, n.exports, i), n.exports
+ }
+
+ return i.d = (t, e) => {
+ for (var r in e) i.o(e, r) && !i.o(t, r) && Object.defineProperty(t, r, {enumerable: !0, get: e[r]})
+ }, i.o = (t, e) => Object.prototype.hasOwnProperty.call(t, e), i(771)
+ })().default
+}));
\ No newline at end of file
diff --git a/src/main/resources/static/js/lay-config.js b/src/main/resources/static/js/lay-config.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/common/common.js b/src/main/resources/static/js/lay-module/common/common.js
old mode 100644
new mode 100755
index 7fab1e5..79dae95
--- a/src/main/resources/static/js/lay-module/common/common.js
+++ b/src/main/resources/static/js/lay-module/common/common.js
@@ -54,7 +54,7 @@ layui.define(['form','table'], function (exports) { //提示:模块也可以
submitPostReq,
formListenFun: function (layFilter, type, path, resultId, reqType) {
form.on(`submit(${layFilter})`, function (data) {
- var value = data.field.content;
+ var value = data.field.payload;
// 定义白名单正则表达式
var whitelistRegex = /^[a-zA-Z0-9_\s]+$/;
diff --git a/src/main/resources/static/js/lay-module/echarts/echarts.js b/src/main/resources/static/js/lay-module/echarts/echarts.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/echarts/echartsTheme.js b/src/main/resources/static/js/lay-module/echarts/echartsTheme.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/iconPicker/iconPickerFa.js b/src/main/resources/static/js/lay-module/iconPicker/iconPickerFa.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/layarea/layarea.js b/src/main/resources/static/js/lay-module/layarea/layarea.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/layuimini/miniAdmin.js b/src/main/resources/static/js/lay-module/layuimini/miniAdmin.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/layuimini/miniMenu.js b/src/main/resources/static/js/lay-module/layuimini/miniMenu.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/layuimini/miniTab.js b/src/main/resources/static/js/lay-module/layuimini/miniTab.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/layuimini/miniTheme.js b/src/main/resources/static/js/lay-module/layuimini/miniTheme.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/layuimini/miniTongji.js b/src/main/resources/static/js/lay-module/layuimini/miniTongji.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/step-lay/step.css b/src/main/resources/static/js/lay-module/step-lay/step.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/step-lay/step.js b/src/main/resources/static/js/lay-module/step-lay/step.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/tableSelect/tableSelect.js b/src/main/resources/static/js/lay-module/tableSelect/tableSelect.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/treetable-lay/treetable.css b/src/main/resources/static/js/lay-module/treetable-lay/treetable.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/treetable-lay/treetable.js b/src/main/resources/static/js/lay-module/treetable-lay/treetable.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/wangEditor/fonts/w-e-icon.woff b/src/main/resources/static/js/lay-module/wangEditor/fonts/w-e-icon.woff
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/wangEditor/wangEditor.css b/src/main/resources/static/js/lay-module/wangEditor/wangEditor.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/wangEditor/wangEditor.js b/src/main/resources/static/js/lay-module/wangEditor/wangEditor.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/wangEditor/wangEditor.min.css b/src/main/resources/static/js/lay-module/wangEditor/wangEditor.min.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/wangEditor/wangEditor.min.js b/src/main/resources/static/js/lay-module/wangEditor/wangEditor.min.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/lay-module/wangEditor/wangEditor.min.js.map b/src/main/resources/static/js/lay-module/wangEditor/wangEditor.min.js.map
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/md5.min.js b/src/main/resources/static/js/md5.min.js
new file mode 100755
index 0000000..b74f9e7
--- /dev/null
+++ b/src/main/resources/static/js/md5.min.js
@@ -0,0 +1,109 @@
+/**
+ * [js-md5]{@link https://github.com/emn178/js-md5}
+ *
+ * @namespace md5
+ * @version 0.7.3
+ * @author Chen, Yi-Cyuan [emn178@gmail.com]
+ * @copyright Chen, Yi-Cyuan 2014-2017
+ * @license MIT
+ */
+!function () {
+ "use strict";
+
+ function t(t) {
+ if (t) d[0] = d[16] = d[1] = d[2] = d[3] = d[4] = d[5] = d[6] = d[7] = d[8] = d[9] = d[10] = d[11] = d[12] = d[13] = d[14] = d[15] = 0, this.blocks = d, this.buffer8 = l; else if (a) {
+ var r = new ArrayBuffer(68);
+ this.buffer8 = new Uint8Array(r), this.blocks = new Uint32Array(r)
+ } else this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+ this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0, this.finalized = this.hashed = !1, this.first = !0
+ }
+
+ var r = "input is invalid type", e = "object" == typeof window, i = e ? window : {};
+ i.JS_MD5_NO_WINDOW && (e = !1);
+ var s = !e && "object" == typeof self,
+ h = !i.JS_MD5_NO_NODE_JS && "object" == typeof process && process.versions && process.versions.node;
+ h ? i = global : s && (i = self);
+ var f = !i.JS_MD5_NO_COMMON_JS && "object" == typeof module && module.exports,
+ o = "function" == typeof define && define.amd,
+ a = !i.JS_MD5_NO_ARRAY_BUFFER && "undefined" != typeof ArrayBuffer, n = "0123456789abcdef".split(""),
+ u = [128, 32768, 8388608, -2147483648], y = [0, 8, 16, 24],
+ c = ["hex", "array", "digest", "buffer", "arrayBuffer", "base64"],
+ p = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""), d = [], l;
+ if (a) {
+ var A = new ArrayBuffer(68);
+ l = new Uint8Array(A), d = new Uint32Array(A)
+ }
+ !i.JS_MD5_NO_NODE_JS && Array.isArray || (Array.isArray = function (t) {
+ return "[object Array]" === Object.prototype.toString.call(t)
+ }), !a || !i.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW && ArrayBuffer.isView || (ArrayBuffer.isView = function (t) {
+ return "object" == typeof t && t.buffer && t.buffer.constructor === ArrayBuffer
+ });
+ var b = function (r) {
+ return function (e) {
+ return new t(!0).update(e)[r]()
+ }
+ }, v = function () {
+ var r = b("hex");
+ h && (r = w(r)), r.create = function () {
+ return new t
+ }, r.update = function (t) {
+ return r.create().update(t)
+ };
+ for (var e = 0; e < c.length; ++e) {
+ var i = c[e];
+ r[i] = b(i)
+ }
+ return r
+ }, w = function (t) {
+ var e = eval("require('crypto')"), i = eval("require('buffer').Buffer"), s = function (s) {
+ if ("string" == typeof s) return e.createHash("md5").update(s, "utf8").digest("hex");
+ if (null === s || void 0 === s) throw r;
+ return s.constructor === ArrayBuffer && (s = new Uint8Array(s)), Array.isArray(s) || ArrayBuffer.isView(s) || s.constructor === i ? e.createHash("md5").update(new i(s)).digest("hex") : t(s)
+ };
+ return s
+ };
+ t.prototype.update = function (t) {
+ if (!this.finalized) {
+ var e, i = typeof t;
+ if ("string" !== i) {
+ if ("object" !== i) throw r;
+ if (null === t) throw r;
+ if (a && t.constructor === ArrayBuffer) t = new Uint8Array(t); else if (!(Array.isArray(t) || a && ArrayBuffer.isView(t))) throw r;
+ e = !0
+ }
+ for (var s, h, f = 0, o = t.length, n = this.blocks, u = this.buffer8; f < o;) {
+ if (this.hashed && (this.hashed = !1, n[0] = n[16], n[16] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = n[7] = n[8] = n[9] = n[10] = n[11] = n[12] = n[13] = n[14] = n[15] = 0), e) if (a) for (h = this.start; f < o && h < 64; ++f) u[h++] = t[f]; else for (h = this.start; f < o && h < 64; ++f) n[h >> 2] |= t[f] << y[3 & h++]; else if (a) for (h = this.start; f < o && h < 64; ++f) (s = t.charCodeAt(f)) < 128 ? u[h++] = s : s < 2048 ? (u[h++] = 192 | s >> 6, u[h++] = 128 | 63 & s) : s < 55296 || s >= 57344 ? (u[h++] = 224 | s >> 12, u[h++] = 128 | s >> 6 & 63, u[h++] = 128 | 63 & s) : (s = 65536 + ((1023 & s) << 10 | 1023 & t.charCodeAt(++f)), u[h++] = 240 | s >> 18, u[h++] = 128 | s >> 12 & 63, u[h++] = 128 | s >> 6 & 63, u[h++] = 128 | 63 & s); else for (h = this.start; f < o && h < 64; ++f) (s = t.charCodeAt(f)) < 128 ? n[h >> 2] |= s << y[3 & h++] : s < 2048 ? (n[h >> 2] |= (192 | s >> 6) << y[3 & h++], n[h >> 2] |= (128 | 63 & s) << y[3 & h++]) : s < 55296 || s >= 57344 ? (n[h >> 2] |= (224 | s >> 12) << y[3 & h++], n[h >> 2] |= (128 | s >> 6 & 63) << y[3 & h++], n[h >> 2] |= (128 | 63 & s) << y[3 & h++]) : (s = 65536 + ((1023 & s) << 10 | 1023 & t.charCodeAt(++f)), n[h >> 2] |= (240 | s >> 18) << y[3 & h++], n[h >> 2] |= (128 | s >> 12 & 63) << y[3 & h++], n[h >> 2] |= (128 | s >> 6 & 63) << y[3 & h++], n[h >> 2] |= (128 | 63 & s) << y[3 & h++]);
+ this.lastByteIndex = h, this.bytes += h - this.start, h >= 64 ? (this.start = h - 64, this.hash(), this.hashed = !0) : this.start = h
+ }
+ return this.bytes > 4294967295 && (this.hBytes += this.bytes / 4294967296 << 0, this.bytes = this.bytes % 4294967296), this
+ }
+ }, t.prototype.finalize = function () {
+ if (!this.finalized) {
+ this.finalized = !0;
+ var t = this.blocks, r = this.lastByteIndex;
+ t[r >> 2] |= u[3 & r], r >= 56 && (this.hashed || this.hash(), t[0] = t[16], t[16] = t[1] = t[2] = t[3] = t[4] = t[5] = t[6] = t[7] = t[8] = t[9] = t[10] = t[11] = t[12] = t[13] = t[14] = t[15] = 0), t[14] = this.bytes << 3, t[15] = this.hBytes << 3 | this.bytes >>> 29, this.hash()
+ }
+ }, t.prototype.hash = function () {
+ var t, r, e, i, s, h, f = this.blocks;
+ this.first ? r = ((r = ((t = ((t = f[0] - 680876937) << 7 | t >>> 25) - 271733879 << 0) ^ (e = ((e = (-271733879 ^ (i = ((i = (-1732584194 ^ 2004318071 & t) + f[1] - 117830708) << 12 | i >>> 20) + t << 0) & (-271733879 ^ t)) + f[2] - 1126478375) << 17 | e >>> 15) + i << 0) & (i ^ t)) + f[3] - 1316259209) << 22 | r >>> 10) + e << 0 : (t = this.h0, r = this.h1, e = this.h2, r = ((r += ((t = ((t += ((i = this.h3) ^ r & (e ^ i)) + f[0] - 680876936) << 7 | t >>> 25) + r << 0) ^ (e = ((e += (r ^ (i = ((i += (e ^ t & (r ^ e)) + f[1] - 389564586) << 12 | i >>> 20) + t << 0) & (t ^ r)) + f[2] + 606105819) << 17 | e >>> 15) + i << 0) & (i ^ t)) + f[3] - 1044525330) << 22 | r >>> 10) + e << 0), r = ((r += ((t = ((t += (i ^ r & (e ^ i)) + f[4] - 176418897) << 7 | t >>> 25) + r << 0) ^ (e = ((e += (r ^ (i = ((i += (e ^ t & (r ^ e)) + f[5] + 1200080426) << 12 | i >>> 20) + t << 0) & (t ^ r)) + f[6] - 1473231341) << 17 | e >>> 15) + i << 0) & (i ^ t)) + f[7] - 45705983) << 22 | r >>> 10) + e << 0, r = ((r += ((t = ((t += (i ^ r & (e ^ i)) + f[8] + 1770035416) << 7 | t >>> 25) + r << 0) ^ (e = ((e += (r ^ (i = ((i += (e ^ t & (r ^ e)) + f[9] - 1958414417) << 12 | i >>> 20) + t << 0) & (t ^ r)) + f[10] - 42063) << 17 | e >>> 15) + i << 0) & (i ^ t)) + f[11] - 1990404162) << 22 | r >>> 10) + e << 0, r = ((r += ((t = ((t += (i ^ r & (e ^ i)) + f[12] + 1804603682) << 7 | t >>> 25) + r << 0) ^ (e = ((e += (r ^ (i = ((i += (e ^ t & (r ^ e)) + f[13] - 40341101) << 12 | i >>> 20) + t << 0) & (t ^ r)) + f[14] - 1502002290) << 17 | e >>> 15) + i << 0) & (i ^ t)) + f[15] + 1236535329) << 22 | r >>> 10) + e << 0, r = ((r += ((i = ((i += (r ^ e & ((t = ((t += (e ^ i & (r ^ e)) + f[1] - 165796510) << 5 | t >>> 27) + r << 0) ^ r)) + f[6] - 1069501632) << 9 | i >>> 23) + t << 0) ^ t & ((e = ((e += (t ^ r & (i ^ t)) + f[11] + 643717713) << 14 | e >>> 18) + i << 0) ^ i)) + f[0] - 373897302) << 20 | r >>> 12) + e << 0, r = ((r += ((i = ((i += (r ^ e & ((t = ((t += (e ^ i & (r ^ e)) + f[5] - 701558691) << 5 | t >>> 27) + r << 0) ^ r)) + f[10] + 38016083) << 9 | i >>> 23) + t << 0) ^ t & ((e = ((e += (t ^ r & (i ^ t)) + f[15] - 660478335) << 14 | e >>> 18) + i << 0) ^ i)) + f[4] - 405537848) << 20 | r >>> 12) + e << 0, r = ((r += ((i = ((i += (r ^ e & ((t = ((t += (e ^ i & (r ^ e)) + f[9] + 568446438) << 5 | t >>> 27) + r << 0) ^ r)) + f[14] - 1019803690) << 9 | i >>> 23) + t << 0) ^ t & ((e = ((e += (t ^ r & (i ^ t)) + f[3] - 187363961) << 14 | e >>> 18) + i << 0) ^ i)) + f[8] + 1163531501) << 20 | r >>> 12) + e << 0, r = ((r += ((i = ((i += (r ^ e & ((t = ((t += (e ^ i & (r ^ e)) + f[13] - 1444681467) << 5 | t >>> 27) + r << 0) ^ r)) + f[2] - 51403784) << 9 | i >>> 23) + t << 0) ^ t & ((e = ((e += (t ^ r & (i ^ t)) + f[7] + 1735328473) << 14 | e >>> 18) + i << 0) ^ i)) + f[12] - 1926607734) << 20 | r >>> 12) + e << 0, r = ((r += ((h = (i = ((i += ((s = r ^ e) ^ (t = ((t += (s ^ i) + f[5] - 378558) << 4 | t >>> 28) + r << 0)) + f[8] - 2022574463) << 11 | i >>> 21) + t << 0) ^ t) ^ (e = ((e += (h ^ r) + f[11] + 1839030562) << 16 | e >>> 16) + i << 0)) + f[14] - 35309556) << 23 | r >>> 9) + e << 0, r = ((r += ((h = (i = ((i += ((s = r ^ e) ^ (t = ((t += (s ^ i) + f[1] - 1530992060) << 4 | t >>> 28) + r << 0)) + f[4] + 1272893353) << 11 | i >>> 21) + t << 0) ^ t) ^ (e = ((e += (h ^ r) + f[7] - 155497632) << 16 | e >>> 16) + i << 0)) + f[10] - 1094730640) << 23 | r >>> 9) + e << 0, r = ((r += ((h = (i = ((i += ((s = r ^ e) ^ (t = ((t += (s ^ i) + f[13] + 681279174) << 4 | t >>> 28) + r << 0)) + f[0] - 358537222) << 11 | i >>> 21) + t << 0) ^ t) ^ (e = ((e += (h ^ r) + f[3] - 722521979) << 16 | e >>> 16) + i << 0)) + f[6] + 76029189) << 23 | r >>> 9) + e << 0, r = ((r += ((h = (i = ((i += ((s = r ^ e) ^ (t = ((t += (s ^ i) + f[9] - 640364487) << 4 | t >>> 28) + r << 0)) + f[12] - 421815835) << 11 | i >>> 21) + t << 0) ^ t) ^ (e = ((e += (h ^ r) + f[15] + 530742520) << 16 | e >>> 16) + i << 0)) + f[2] - 995338651) << 23 | r >>> 9) + e << 0, r = ((r += ((i = ((i += (r ^ ((t = ((t += (e ^ (r | ~i)) + f[0] - 198630844) << 6 | t >>> 26) + r << 0) | ~e)) + f[7] + 1126891415) << 10 | i >>> 22) + t << 0) ^ ((e = ((e += (t ^ (i | ~r)) + f[14] - 1416354905) << 15 | e >>> 17) + i << 0) | ~t)) + f[5] - 57434055) << 21 | r >>> 11) + e << 0, r = ((r += ((i = ((i += (r ^ ((t = ((t += (e ^ (r | ~i)) + f[12] + 1700485571) << 6 | t >>> 26) + r << 0) | ~e)) + f[3] - 1894986606) << 10 | i >>> 22) + t << 0) ^ ((e = ((e += (t ^ (i | ~r)) + f[10] - 1051523) << 15 | e >>> 17) + i << 0) | ~t)) + f[1] - 2054922799) << 21 | r >>> 11) + e << 0, r = ((r += ((i = ((i += (r ^ ((t = ((t += (e ^ (r | ~i)) + f[8] + 1873313359) << 6 | t >>> 26) + r << 0) | ~e)) + f[15] - 30611744) << 10 | i >>> 22) + t << 0) ^ ((e = ((e += (t ^ (i | ~r)) + f[6] - 1560198380) << 15 | e >>> 17) + i << 0) | ~t)) + f[13] + 1309151649) << 21 | r >>> 11) + e << 0, r = ((r += ((i = ((i += (r ^ ((t = ((t += (e ^ (r | ~i)) + f[4] - 145523070) << 6 | t >>> 26) + r << 0) | ~e)) + f[11] - 1120210379) << 10 | i >>> 22) + t << 0) ^ ((e = ((e += (t ^ (i | ~r)) + f[2] + 718787259) << 15 | e >>> 17) + i << 0) | ~t)) + f[9] - 343485551) << 21 | r >>> 11) + e << 0, this.first ? (this.h0 = t + 1732584193 << 0, this.h1 = r - 271733879 << 0, this.h2 = e - 1732584194 << 0, this.h3 = i + 271733878 << 0, this.first = !1) : (this.h0 = this.h0 + t << 0, this.h1 = this.h1 + r << 0, this.h2 = this.h2 + e << 0, this.h3 = this.h3 + i << 0)
+ }, t.prototype.hex = function () {
+ this.finalize();
+ var t = this.h0, r = this.h1, e = this.h2, i = this.h3;
+ return n[t >> 4 & 15] + n[15 & t] + n[t >> 12 & 15] + n[t >> 8 & 15] + n[t >> 20 & 15] + n[t >> 16 & 15] + n[t >> 28 & 15] + n[t >> 24 & 15] + n[r >> 4 & 15] + n[15 & r] + n[r >> 12 & 15] + n[r >> 8 & 15] + n[r >> 20 & 15] + n[r >> 16 & 15] + n[r >> 28 & 15] + n[r >> 24 & 15] + n[e >> 4 & 15] + n[15 & e] + n[e >> 12 & 15] + n[e >> 8 & 15] + n[e >> 20 & 15] + n[e >> 16 & 15] + n[e >> 28 & 15] + n[e >> 24 & 15] + n[i >> 4 & 15] + n[15 & i] + n[i >> 12 & 15] + n[i >> 8 & 15] + n[i >> 20 & 15] + n[i >> 16 & 15] + n[i >> 28 & 15] + n[i >> 24 & 15]
+ }, t.prototype.toString = t.prototype.hex, t.prototype.digest = function () {
+ this.finalize();
+ var t = this.h0, r = this.h1, e = this.h2, i = this.h3;
+ return [255 & t, t >> 8 & 255, t >> 16 & 255, t >> 24 & 255, 255 & r, r >> 8 & 255, r >> 16 & 255, r >> 24 & 255, 255 & e, e >> 8 & 255, e >> 16 & 255, e >> 24 & 255, 255 & i, i >> 8 & 255, i >> 16 & 255, i >> 24 & 255]
+ }, t.prototype.array = t.prototype.digest, t.prototype.arrayBuffer = function () {
+ this.finalize();
+ var t = new ArrayBuffer(16), r = new Uint32Array(t);
+ return r[0] = this.h0, r[1] = this.h1, r[2] = this.h2, r[3] = this.h3, t
+ }, t.prototype.buffer = t.prototype.arrayBuffer, t.prototype.base64 = function () {
+ for (var t, r, e, i = "", s = this.array(), h = 0; h < 15;) t = s[h++], r = s[h++], e = s[h++], i += p[t >>> 2] + p[63 & (t << 4 | r >>> 4)] + p[63 & (r << 2 | e >>> 6)] + p[63 & e];
+ return t = s[h], i += p[t >>> 2] + p[t << 4 & 63] + "=="
+ };
+ var _ = v();
+ f ? module.exports = _ : (i.md5 = _, o && define(function () {
+ return _
+ }))
+}();
\ No newline at end of file
diff --git a/src/main/resources/static/js/sec-tip.js b/src/main/resources/static/js/sec-tip.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/js/staticcode.js b/src/main/resources/static/js/staticcode.js
old mode 100644
new mode 100755
index 828d911..d50001f
--- a/src/main/resources/static/js/staticcode.js
+++ b/src/main/resources/static/js/staticcode.js
@@ -4,9 +4,9 @@
* @email: whgojp@foxmail.com
* @Date: 2024/5/19 19:03
*/
-const vul1ReflectRaw = "// 原生漏洞场景,未加任何过滤,Controller接口返回Json类型结果\n" +
- "public R vul1(String content) {\n" +
- " return R.ok(content);\n" +
+const vul1ReflectRaw = "// 原生漏洞场景,未加任何过滤,Controller接口返回JSON类型结果\n" +
+ "public R vul1(String payload) {\n" +
+ " return R.ok(payload);\n" +
"}\n" +
"// R 是对返回结果的封装工具util\n" +
"// 返回结果:\n" +
@@ -14,28 +14,28 @@ const vul1ReflectRaw = "// 原生漏洞场景,未加任何过滤,Controller接
"// \"msg\": \"\",\n" +
"// \"code\": 0\n" +
"// }\n" +
- "// payload在json中是不会触发xss的 需要解析到页面中\n" +
+ "// JSON响应本身通常不会直接执行脚本;前端若把字段用innerHTML等方式写入页面,才会触发XSS\n" +
"\n" +
"// 原生漏洞场景,未加任何过滤,Controller接口返回String类型结果\n" +
- "public String vul2(String content) {\n" +
- " return content;\n" +
+ "public String vul2(String payload) {\n" +
+ " return payload;\n" +
"}"
const vul2ReflectContentType = "// Tomcat内置HttpServletResponse,Content-Type导致反射XSS\n" +
- "public void vul3(String type,String content, HttpServletResponse response) {\n" +
+ "public void vul3(String type,String payload, HttpServletResponse response) {\n" +
" switch (type) {\n" +
" case \"html\":\n" +
- " response.getWriter().print(content);\n" +
+ " response.getWriter().print(payload);\n" +
" response.setContentType(\"text/html;charset=utf-8\");\n" +
" response.getWriter().flush();\n" +
" break;\n" +
" case \"plain\":\n" +
- " response.getWriter().print(content);\n" +
+ " response.getWriter().print(payload);\n" +
" response.setContentType(\"text/plain;charset=utf-8\");\n" +
" response.getWriter().flush();\n" +
" ...\n" +
" }\n" +
"}"
-const safe1CheckUserInput = "// 对用户输入的数据进行验证和过滤,确保不包含恶意代码。使用白名单过滤,只允许特定类型的输入,如纯文本或指定格式的数据\n" +
+const safe1CheckUserInput = "// 使用白名单限制输入格式,适合约束字段类型;最终仍需根据输出位置进行上下文编码\n" +
"// 前端校验代码\n" +
"var whitelistRegex = /^[a-zA-Z0-9_\\s]+$/;\n" +
"\n" +
@@ -51,55 +51,56 @@ const safe1CheckUserInput = "// 对用户输入的数据进行验证和过滤,
"private static final String WHITELIST_REGEX = \"^[a-zA-Z0-9_\\\\s]+$\";\n" +
"private static final Pattern pattern = Pattern.compile(WHITELIST_REGEX);\n" +
"\n" +
- "Matcher matcher = pattern.matcher(content);\n" +
+ "Matcher matcher = pattern.matcher(payload);\n" +
"if (matcher.matches()){\n" +
- " return R.ok(content);\n" +
+ " return R.ok(payload);\n" +
"}else return R.error(\"输入内容包含非法字符,请检查输入\");"
-const safe2CSP = "// 内容安全策略(Content Security Policy)是一种由浏览器实施的安全机制,旨在减少和防范跨站脚本攻击(XSS)等安全威胁。它通过允许网站管理员定义哪些内容来源是可信任的,从而防止恶意内容的加载和执行\n" +
+const safe2CSP = "// 内容安全策略(Content Security Policy)是浏览器实施的额外防护层,可降低恶意脚本加载和执行风险,但不能替代输出编码与安全DOM/模板用法\n" +
"// 前端Meta配置\n" +
" \n" +
"\n" +
"\n" +
"// 后端Header配置\n" +
- "public String safe2(String content,HttpServletResponse response) {\n" +
- " response.setHeader(\"Content-Security-Policy\",\"default-src self\");\n" +
- " return content;\n" +
+ "public String safe2(String payload,HttpServletResponse response) {\n" +
+ " response.setHeader(\"Content-Security-Policy\", \"default-src 'self'; script-src 'self'\");\n" +
+ " response.setHeader(\"Content-Security-Policy-Report-Only\", \"default-src 'self'; report-uri /xss/reflect/csp-report-endpoint\");\n" +
+ " return payload;\n" +
"}"
-const safe3EntityEscape = '// 特殊字符实体转义是一种将HTML中的特殊字符转换为预定义实体表示的过程\n' +
- '// 这种转义是为了确保在HTML页面中正确显示特定字符,同时避免它们被浏览器误解为HTML标签或JavaScript代码的一部分,从而导致页面结构混乱或安全漏洞\n' +
- 'public R safe3(@ApiParam(String type, String content) {\n' +
+const safe3EntityEscape = '// HTML正文输出编码会将特殊字符转换为HTML实体,避免浏览器把不可信数据解析为标签或脚本\n' +
+ '// 注意:HTML属性、URL、JavaScript字符串、CSS等不同上下文需要使用不同的编码或白名单校验策略\n' +
+ 'public R safe3(@ApiParam(String type, String payload) {\n' +
' String filterContented = "";\n' +
' switch (type){\n' +
' case "manual":\n' +
- ' content = StringUtils.replace(content, "&", "&");\n' +
- ' content = StringUtils.replace(content, "<", "<");\n' +
- ' content = StringUtils.replace(content, ">", ">");\n' +
- ' content = StringUtils.replace(content, "\\"", """);\n' +
- ' content = StringUtils.replace(content, "\'", "'");\n' +
- ' content = StringUtils.replace(content, "/", "/");\n' +
- ' filterContented = content;\n' +
+ ' payload = StringUtils.replace(payload, "&", "&");\n' +
+ ' payload = StringUtils.replace(payload, "<", "<");\n' +
+ ' payload = StringUtils.replace(payload, ">", ">");\n' +
+ ' payload = StringUtils.replace(payload, "\\"", """);\n' +
+ ' payload = StringUtils.replace(payload, "\'", "'");\n' +
+ ' payload = StringUtils.replace(payload, "/", "/");\n' +
+ ' filterContented = payload;\n' +
' break;\n' +
' case "spring":\n' +
- ' filterContented = HtmlUtils.htmlEscape(content);\n' +
+ ' filterContented = HtmlUtils.htmlEscape(payload);\n' +
' break;\n' +
' ...\n' +
' }\n' +
'}'
-const safe4HttpOnly = "// HttpOnly是HTTP响应头属性,用于增强Web应用程序安全性。它防止客户端脚本访问(只能通过http/https协议访问)带有HttpOnly标记的 cookie,从而减少跨站点脚本攻击(XSS)的风险\n" +
+const safe4HttpOnly = "// HttpOnly可以阻止客户端脚本直接读取带有该属性的Cookie,降低XSS窃取Cookie的影响,但不能修复XSS本身\n" +
"// 单个接口配置\n" +
- "public R safe4(String content, HttpServletRequest request,HttpServletResponse response) {\n" +
- " Cookie cookie = request.getCookies()[ueditor];\n" +
+ "public R safe4(String payload, HttpServletRequest request,HttpServletResponse response) {\n" +
+ " Cookie cookie = request.getCookies()[0];\n" +
" cookie.setHttpOnly(true); // 设置为 HttpOnly\n" +
" cookie.setMaxAge(600); // 这里设置生效时间为十分钟\n" +
" cookie.setPath(\"/\");\n" +
" response.addCookie(cookie);\n" +
- " return R.ok(content);\n" +
+ " return R.ok(payload);\n" +
"}\n" +
"\n" +
"// 全局配置\n" +
- "// ueditor、application.yml配置\n" +
+ "// application.yml配置\n" +
"server:\n" +
" servlet:\n" +
" session:\n" +
@@ -118,11 +119,11 @@ const safe4HttpOnly = "// HttpOnly是HTTP响应头属性,用于增强Web应用
" ...\n" +
"}"
-const vul1StoreRaw = "// 原生漏洞场景,未加任何过滤,将用户输入存储到数据库中\n" +
+const vul1StoreRaw = "// 原生漏洞场景,未加任何过滤,将用户输入和User-Agent持久化;后续页面不安全渲染时触发存储型XSS\n" +
"// Controller层\n" +
- "public R vul(String content,HttpServletRequest request) {\n" +
+ "public R vul(String payload,HttpServletRequest request) {\n" +
" String ua = request.getHeader(\"User-Agent\");\n" +
- " final int code = xssService.insertOne(content,ua);\n" +
+ " final int code = xssService.insertOne(payload,ua);\n" +
" ...\n" +
"}\n" +
"// Service层\n" +
@@ -139,7 +140,7 @@ const vul1StoreRaw = "// 原生漏洞场景,未加任何过滤,将用户输入
" values (#{content,jdbcType=VARCHAR},#{ua,jdbcType=VARCHAR}, #{date,jdbcType=VARCHAR})\n" +
" "
-const safe1StoreEntityEscape = "// 表格数据渲染\n" +
+const safe1StoreEntityEscape = "// 表格数据渲染:数据库仍保存原始值,输出到HTML页面前按HTML正文文本编码\n" +
"table.render({\n" +
"\t...\n" +
" cols: [\n" +
@@ -151,10 +152,13 @@ const safe1StoreEntityEscape = "// 表格数据渲染\n" +
" return escapeHtml(d.ua); \n" +
" }},\n" +
" \t...\n" +
- "// 方法一、HTML 实体转义函数\n" +
+ "// 方法一、HTML正文输出编码函数\n" +
"function escapeHtml(html) {\n" +
+ " if (html === null || html === undefined) {\n" +
+ " return '';\n" +
+ " }\n" +
" var text = document.createElement(\"textarea\");\n" +
- " text.textContent = html;\n" +
+ " text.textContent = String(html);\n" +
" return text.innerHTML;\n" +
"}\n" +
"// 方法二、JavaScript的文本节点\n" +
@@ -163,31 +167,85 @@ const safe1StoreEntityEscape = "// 表格数据渲染\n" +
"// 方法三、jQuery的text()方法\n" +
"$('#element').text(htmlContent);\n"
-const vul1DomRaw = "// innerHTML\n" +
+const vul1DomRaw = "// 1. innerHTML XSS\n" +
"form.on('submit(vul1-dom-raw)', function (data) {\n" +
" var userInput = document.getElementById('vul1-dom-raw-input').value;\n" +
" var outputDiv = document.getElementById('vul-dom-raw-result');\n" +
- " outputDiv.innerHTML = userInput;\n" +
+ " outputDiv.innerHTML = userInput; // 漏洞点:直接使用innerHTML插入用户输入\n" +
" return false;\n" +
"});\n" +
"\n" +
- "// href跳转场景\n" +
+ "// 2. LocalStorage XSS\n" +
+ "form.on('submit(vul3-dom-raw-submit)', function (data) {\n" +
+ " localStorage.setItem('vul4-dom-raw', document.getElementById('vul4-dom-raw-input').value);\n" +
+ " var storedData = localStorage.getItem('vul4-dom-raw');\n" +
+ " document.getElementById('vul-dom-raw-result').innerHTML = storedData; // 漏洞点:从存储读取后直接插入\n" +
+ " return false;\n" +
+ "});\n" +
+ "\n" +
+ "// 3. href跳转XSS\n" +
"var hash = location.hash;\n" +
"if(hash){\n" +
- " var url = hash.substring(ueditor);\n" +
+ " var url = hash.substring(1); // 去掉#号\n" +
" console.log(url);\n" +
- " location.href = url;\n" +
+ " location.href = url; // 漏洞点:直接使用hash部分作为跳转URL\n" +
"}\n" +
"\n" +
- "// DOM存储注入\n" +
- "form.on('submit(vul3-dom-raw-submit)', function (data) {\n" +
- " localStorage.setItem('vul4-dom-raw', document.getElementById('vul4-dom-raw-input').value);\n" +
- " var storedData = localStorage.getItem('vul4-dom-raw');\n" +
- " document.getElementById('vul-dom-raw-result').innerHTML = storedData;\n" +
+ "// 4. Location对象XSS\n" +
+ "form.on('submit(location-xss)', function(data) {\n" +
+ " var payload = data.field.locationPayload;\n" +
+ " window.location = payload; // 漏洞点:直接使用用户输入修改location\n" +
+ " return false;\n" +
+ "});\n" +
+ "\n" +
+ "// 5. Eval执行XSS\n" +
+ "form.on('submit(eval-xss)', function(data) {\n" +
+ " var payload = data.field.evalPayload;\n" +
+ " eval(payload); // 漏洞点:直接执行用户输入的JavaScript代码\n" +
+ " return false;\n" +
+ "});\n" +
+ "\n" +
+ "// 6. Document对象XSS\n" +
+ "form.on('submit(document-write)', function(data) {\n" +
+ " var payload = data.field.documentPayload;\n" +
+ " document.write(payload); // 漏洞点:直接写入用户输入的HTML\n" +
+ " document.close();\n" +
+ " return false;\n" +
+ "});\n" +
+ "form.on('submit(document-domain)', function(data) {\n" +
+ " var payload = data.field.documentPayload;\n" +
+ " document.domain = payload; // 风险点:直接修改document.domain会放宽同源边界或造成异常行为\n" +
" return false;\n" +
- "})"
+ "});"
-const vul1OtherUpload = "public String uploadFile(MultipartFile file, String suffix,String path) throws IOException {\n" +
+const safeDomCode = "// 1. 普通文本输出:使用textContent,不解析HTML\n" +
+ "document.getElementById('safe-dom-result').textContent = userInput;\n" +
+ "\n" +
+ "// 2. URL跳转:校验协议白名单,拒绝javascript:、data:等危险协议\n" +
+ "var url = new URL(userInput, window.location.origin);\n" +
+ "var allowedProtocols = ['http:', 'https:'];\n" +
+ "if (allowedProtocols.indexOf(url.protocol) === -1) {\n" +
+ " throw new Error('dangerous protocol');\n" +
+ "}\n" +
+ "\n" +
+ "// 3. 替代eval:使用命令白名单映射,而不是执行用户输入\n" +
+ "var actions = {\n" +
+ " showTime: function () { return new Date().toLocaleString(); },\n" +
+ " showLocation: function () { return window.location.pathname; }\n" +
+ "};\n" +
+ "var action = actions[userInput];\n" +
+ "if (action) {\n" +
+ " action();\n" +
+ "}\n" +
+ "\n" +
+ "// 4. DOM API:创建文本节点,不拼接HTML字符串\n" +
+ "var node = document.createTextNode(userInput);\n" +
+ "element.appendChild(node);\n" +
+ "\n" +
+ "// 如果业务必须展示富文本,应先使用白名单HTML净化库处理后再渲染\n"
+
+const vul1OtherUpload = "// 上传可被浏览器或预览服务解析的HTML/SVG/XML/PDF等文件,后续访问文件时可能触发XSS或内容安全问题\n" +
+ "public String uploadFile(MultipartFile file, String suffix,String path) throws IOException {\n" +
" String uploadFolderPath = sysConstant.getUploadFolder();\n" +
" try {\n" +
" String fileName = +DateUtil.current() + \".\"+suffix;\n" +
@@ -203,11 +261,12 @@ const vul1OtherUpload = "public String uploadFile(MultipartFile file, String suf
" }\n" +
"}"
-const vul2OtherTemplate = "public String handleTemplateInjection(String content,String type, Model model) {\n" +
+const vul2OtherTemplate = "// th:utext会把内容作为HTML渲染;th:text会进行HTML转义\n" +
+ "public String handleTemplateInjection(String payload,String type, Model model) {\n" +
" if (\"html\".equals(type)) {\n" +
- " model.addAttribute(\"html\", content);\n" +
+ " model.addAttribute(\"html\", payload);\n" +
" } else if (\"text\".equals(type)) {\n" +
- " model.addAttribute(\"text\", content);\n" +
+ " model.addAttribute(\"text\", payload);\n" +
" }\n" +
" return \"vul/xss/other\";\n" +
"}\n" +
@@ -234,6 +293,22 @@ const vul3SCMSec = "// jQuery依赖\n" +
"\n" +
"// Ueditor编辑器未做任何限制 抓上传数据包后,可以上传任意类型文件";
+const vulHtml5 = "1、PostMessage XSS\n" +
+ "// 接收端:直接使用innerHTML插入消息\n" +
+ "window.addEventListener('message', function(event) {\n" +
+ " // 故意不验证origin\n" +
+ " document.getElementById('messageContainer').innerHTML = event.data;\n" +
+ "});\n" +
+ "2、WebSocket XSS\n" +
+ "// 客户端:直接使用innerHTML插入消息\n" +
+ "ws.onmessage = function(event) {\n" +
+ " document.getElementById('wsMessageContainer').innerHTML = event.data;\n" +
+ "};\n" +
+ "// 服务端:直接广播用户输入\n" +
+ "protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {\n" +
+ " broadcast(message.getPayload());\n" +
+ "}"
+
const vul1RawJoint = "// 原生sql语句动态拼接 参数未进行任何处理\n" +
"public R vul1(String type,String id,String username,String password) {\n" +
" //注册数据库驱动类\n" +
@@ -256,7 +331,7 @@ const vul1RawJoint = "// 原生sql语句动态拼接 参数未进行任何处理
" conn.close();\n" +
" return R.ok(message);\n" +
" case \"delete\":\n" +
- " sql = \"DELETE FROM users WHERE id = '\" + id + \"'\";\n" +
+ " sql = \"DELETE FROM sqli WHERE id = '\" + id + \"'\";\n" +
" rowsAffected = stmt.executeUpdate(sql);\n" +
" ...\n" +
" case \"update\":\n" +
@@ -264,7 +339,7 @@ const vul1RawJoint = "// 原生sql语句动态拼接 参数未进行任何处理
" rowsAffected = stmt.executeUpdate(sql);\n" +
" ...\n" +
" case \"select\":\n" +
- " sql = \"SELECT * FROM users WHERE id = \" + id;\n" +
+ " sql = \"SELECT * FROM sqli WHERE id = \" + id;\n" +
" ResultSet rs = stmt.executeQuery(sql);\n" +
" ...\n" +
" }\n" +
@@ -282,7 +357,7 @@ const vul2prepareStatementJoint = "// 虽然使用了conn.prepareStatement(sql)
" rowsAffected = stmt.executeUpdate(sql);\n" +
" ...\n" +
" case \"delete\":\n" +
- " sql = \"DELETE FROM users WHERE id = '\" + id + \"'\";\n" +
+ " sql = \"DELETE FROM sqli WHERE id = '\" + id + \"'\";\n" +
" stmt = conn.prepareStatement(sql);\n" +
" rowsAffected = stmt.executeUpdate(sql);\n" +
" ...\n" +
@@ -292,7 +367,7 @@ const vul2prepareStatementJoint = "// 虽然使用了conn.prepareStatement(sql)
" rowsAffected = stmt.executeUpdate(sql);\n" +
" ...\n" +
" case \"select\":\n" +
- " sql = \"SELECT * FROM users WHERE id = \" + id;\n" +
+ " sql = \"SELECT * FROM sqli WHERE id = \" + id;\n" +
" stmt = conn.prepareStatement(sql);\n" +
" ResultSet rs = stmt.executeQuery(sql);\n" +
" ...\n" +
@@ -313,7 +388,7 @@ const vul3JdbcTemplateJoint = "// JDBCTemplate是Spring对JDBC的封装,底层
" rowsAffected = jdbctemplate.update(sql);\n" +
" ...\n" +
" case \"delete\":\n" +
- " sql = \"DELETE FROM users WHERE id = '\" + id + \"'\";\n" +
+ " sql = \"DELETE FROM sqli WHERE id = '\" + id + \"'\";\n" +
" rowsAffected = jdbctemplate.update(sql);\n" +
" ...\n" +
" case \"update\":\n" +
@@ -321,8 +396,8 @@ const vul3JdbcTemplateJoint = "// JDBCTemplate是Spring对JDBC的封装,底层
" rowsAffected = jdbctemplate.update(sql);\n" +
" ...\n" +
" case \"select\":\n" +
- " sql = \"SELECT * FROM users WHERE id = \" + id;\n" +
- " stringObjectMap = jdbctemplate.queryForMap(sql);\n" +
+ " sql = \"SELECT * FROM sqli WHERE id = \" + id;\n" +
+ " resultList = jdbctemplate.queryForList(sql);\n" +
" ...\n" +
" }\n" +
"}"
@@ -334,17 +409,17 @@ const safe1PrepareStatementParametric = "// 采用预编译的方法,使用?
" switch (type) {\n" +
" case \"add\":\n" +
" // 这里可以看到使用了?占位符 sql语句和参数进行分离\n" +
- " sql = \"INSERT INTO users (username, password) VALUES (?, ?)\"; \n" +
+ " sql = \"INSERT INTO sqli (username, password) VALUES (?, ?)\"; \n" +
" stmt = conn.prepareStatement(sql);\n" +
" // 参数化处理\n" +
- " stmt.setString(ueditor, username); \n" +
+ " stmt.setString(1, username); \n" +
" stmt.setString(2, password);\n" +
" // 使用预编译时 不需要传递sql语句\n" +
" rowsAffected = stmt.executeUpdate();\n" +
" case \"delete\":\n" +
- " sql = \"DELETE FROM users WHERE id = ?\";\n" +
+ " sql = \"DELETE FROM sqli WHERE id = ?\";\n" +
" stmt = conn.prepareStatement(sql);\n" +
- " stmt.setString(ueditor, id);\n" +
+ " stmt.setString(1, id);\n" +
" rowsAffected = stmt.executeUpdate();\n" +
" ...\n" +
" case \"update\":\n" +
@@ -353,12 +428,12 @@ const safe1PrepareStatementParametric = "// 采用预编译的方法,使用?
" stmt.setString(1, username); \n" +
" stmt.setString(2, password);\n" +
" stmt.setString(3, id);\n" +
- " stmt.executeUpdate();\n" +
+ " rowsAffected = stmt.executeUpdate();\n" +
" ...\n" +
" case \"select\":\n" +
- " sql = \"SELECT * FROM users WHERE id = ?\";\n" +
+ " sql = \"SELECT * FROM sqli WHERE id = ?\";\n" +
" stmt = conn.prepareStatement(sql);\n" +
- " stmt.setString(ueditor, id);\n" +
+ " stmt.setString(1, id);\n" +
" ResultSet rs = stmt.executeQuery();\n" +
" ...\n" +
" }\n" +
@@ -377,20 +452,21 @@ const safe2JdbcTemplatePrepareStatementParametric = "// JDBCTemplate预编译
" rowsAffected = jdbctemplate.update(sql, username, password);\n" +
" ...\n" +
" case \"delete\":\n" +
- " sql = \"DELETE FROM users WHERE id = ?\";\n" +
+ " sql = \"DELETE FROM sqli WHERE id = ?\";\n" +
" rowsAffected = jdbctemplate.update(sql, id);\n" +
" ...\n" +
" case \"update\":\n" +
" sql = \"UPDATE sqli SET username = ?, password = ? WHERE id = ?\";\n" +
- " rowsAffected = jdbctemplate.update(sql, username, id);\n" +
+ " rowsAffected = jdbctemplate.update(sql, username, password, id);\n" +
" ...\n" +
" case \"select\":\n" +
- " sql = \"SELECT * FROM users WHERE id = ?\";\n" +
+ " sql = \"SELECT * FROM sqli WHERE id = ?\";\n" +
" stringObjectMap = jdbctemplate.queryForMap(sql, id);\n" +
" ...\n" +
" }\n" +
"}\n"
-const safe3BlacklistcheckSqlBlackList = "// 检测用户输入是否存在敏感字符:'、;、--、+、,、%、=、>、<、*、(、)、and、or、exeinsert、select、delete、update、count、drop、chr、midmaster、truncate、char、declare\n" +
+const safe3BlacklistcheckSqlBlackList = "// 黑名单只能作为辅助检测或拦截,不应替代参数化查询。\n" +
+ "// 遗漏关键字、编码绕过、语法变形都可能导致绕过。\n" +
"public R safe3(String type,String id,String username,String password) {\n" +
" Class.forName(\"com.mysql.cj.jdbc.Driver\");\n" +
" Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPass);\n" +
@@ -400,28 +476,28 @@ const safe3BlacklistcheckSqlBlackList = "// 检测用户输入是否存在敏感
" if (checkUserInput.checkSqlBlackList(username) || checkUserInput.checkSqlBlackList(password)) {\n" +
" return R.error(\"黑名单检测到非法SQL注入!\");\n" +
" } else {\n" +
- " sql = \"INSERT INTO users (username, password) VALUES ('\" + username + \"', '\" + password + \"')\";\n" +
+ " sql = \"INSERT INTO sqli (username, password) VALUES ('\" + username + \"', '\" + password + \"')\";\n" +
" rowsAffected = stmt.executeUpdate(sql);\n" +
" ...\n" +
" case \"delete\":\n" +
" if (checkUserInput.checkSqlBlackList(id)) {\n" +
" return R.error(\"黑名单检测到非法SQL注入!\");\n" +
" } else {\n" +
- " sql = \"DELETE FROM users WHERE id = '\" + id + \"'\";\n" +
+ " sql = \"DELETE FROM sqli WHERE id = '\" + id + \"'\";\n" +
" rowsAffected = stmt.executeUpdate(sql);\n" +
" ...\n" +
" case \"update\":\n" +
" if (checkUserInput.checkSqlBlackList(id) || checkUserInput.checkSqlBlackList(username) || checkUserInput.checkSqlBlackList(password)) {\n" +
" return R.error(\"黑名单检测到非法SQL注入!\");\n" +
" } else {\n" +
- " sql = \"UPDATE users SET password = '\" + password + \"', username = '\" + username + \"' WHERE id = '\" + id + \"'\";\n" +
+ " sql = \"UPDATE sqli SET password = '\" + password + \"', username = '\" + username + \"' WHERE id = '\" + id + \"'\";\n" +
" rowsAffected = stmt.executeUpdate(sql);\n" +
" ...\n" +
" case \"select\":\n" +
" if (checkUserInput.checkSqlBlackList(id)) {\n" +
" return R.error(\"黑名单检测到非法SQL注入!\");\n" +
" } else {\n" +
- " sql = \"SELECT * FROM users WHERE id = \" + id;\n" +
+ " sql = \"SELECT * FROM sqli WHERE id = \" + id;\n" +
" ResultSet rs = stmt.executeQuery(sql);\n" +
" ...\n" +
" }\n" +
@@ -433,46 +509,47 @@ const safe4RequestRarameterValidate = "// 强制类型转换 对用户请求参
" Statement stmt = conn.createStatement();\n" +
" message = checkUserInput.checkUser(id);\n" +
" if (!message.isEmpty()) return R.error(message);\n" +
- " sql = \"SELECT * FROM users WHERE id = \" + id;\n" +
+ " sql = \"SELECT * FROM sqli WHERE id = \" + id;\n" +
" ResultSet rs = stmt.executeQuery(sql);\n" +
" ...\n" +
"}"
-const safe4EASAPIFilter = "// ESAPI提供了多种输入验证API,提供对XSS攻击和SQL注入攻击等的防护\n" +
- "public R safe4(String id) {\n" +
+const safe4EASAPIFilter = "// encodeForSQL是历史方案或特定数据库Codec场景下的补充手段,不推荐作为首选修复。\n" +
+ "// SQL注入首选修复仍然是参数化查询。\n" +
+ "public R safe5(String id) {\n" +
" Codec oracleCodec = new OracleCodec();\n" +
" Class.forName(\"com.mysql.cj.jdbc.Driver\");\n" +
" Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPass);\n" +
"\n" +
" Statement stmt = conn.createStatement();\n" +
- " // 使用了 Oracle 的编解码器 OracleCodec 和 ESAPI 库来对 ID 进行编码,以防止 SQL 注入攻击。\n" +
+ " // 使用OracleCodec对ID进行SQL编码,仅作为特定场景补充。\n" +
" String sql = \"select * from sqli where id = '\" + ESAPI.encoder().encodeForSQL(oracleCodec, id) + \"'\";\n" +
" // String sql = \"select * from sqli where id = '\" + id + \"'\";\n" +
- " String sql = \"select * from users where id = '\" + id + \"'\";\n" +
" ResultSet rs = stmt.executeQuery(sql);\n" +
"}"
-const special1OrderBy = "// ORDER BY关键字用于按升序或降序对结果集进行排序。 由于order by后面需要紧跟column_name,而预编译是参数化字符串,而order by后面紧跟字符串就会不支持原有功能 使用默认排序,因此通常防御order by注入需要使用白名单的方式\n" +
+const special1OrderBy = "// 占位符只能绑定“值”,不能绑定列名、表名、关键字、排序方向等SQL结构。\n" +
+ "// ORDER BY动态字段应使用枚举映射或白名单。\n" +
"public R special1OrderBy(String type,String field) {\n" +
" Class.forName(\"com.mysql.cj.jdbc.Driver\");\n" +
" Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPass);\n" +
" PreparedStatement preparedStatement;\n" +
" switch (type) {\n" +
" case \"raw\":\n" +
- " sql = \"SELECT * FROM users ORDER BY \" + field;\n" +
+ " sql = \"SELECT * FROM sqli ORDER BY \" + field;\n" +
" preparedStatement = conn.prepareStatement(sql);\n" +
" rs = preparedStatement.executeQuery();\n" +
" ...\n" +
" case \"prepareStatement\":\n" +
- " // 可以测试下 预编译没有报错 不过插入语句不生效 默认使用主键升序\n" +
- " sql = \"select * from users order by ?\";\n" +
+ " // ORDER BY ? 会把字段名当作普通值或表达式处理,不会按传入字段排序。\n" +
+ " sql = \"select * from sqli order by ?\";\n" +
" preparedStatement = conn.prepareStatement(sql);\n" +
- " preparedStatement.setString(ueditor, field);\n" +
+ " preparedStatement.setString(1, field);\n" +
" rs = preparedStatement.executeQuery();\n" +
" ...\n" +
" case \"writeList\":\n" +
- " sql = \"SELECT * FROM users ORDER BY \" + field;\n" +
- " if (checkUserInput.chechSqlWhiteList(field)) {\n" +
+ " if (!checkUserInput.checkSqlWhiteList(field)) {\n" +
" return R.error(\"field字段不合法!\");\n" +
" }\n" +
+ " sql = \"SELECT * FROM sqli ORDER BY \" + field;\n" +
" preparedStatement = conn.prepareStatement(sql);\n" +
" rs = preparedStatement.executeQuery();\n" +
" }\n" +
@@ -520,11 +597,52 @@ const special3Limit = "public R special3Limit(String type,String size) {\n" +
" case \"prepareStatement\":\n" +
" sql = \"SELECT * FROM sqli ORDER BY id DESC LIMIT ?\";\n" +
" preparedStatement = conn.prepareStatement(sql);\n" +
- " preparedStatement.setString(1, size);\n" +
+ " preparedStatement.setInt(1, Integer.parseInt(size));\n" +
" rs = preparedStatement.executeQuery();\n" +
" ...\n" +
" }\n" +
"}"
+const special4SecondOrder = "// 第一步:参数化写入恶意数据,此时不触发SQL注入。\n" +
+ "public R special4SecondOrder(String type,String id,String username,String password) {\n" +
+ " switch (type) {\n" +
+ " case \"store\":\n" +
+ " String insertSql = \"INSERT INTO sqli (username, password) VALUES (?, ?)\";\n" +
+ " PreparedStatement ps = conn.prepareStatement(insertSql, Statement.RETURN_GENERATED_KEYS);\n" +
+ " ps.setString(1, username);\n" +
+ " ps.setString(2, password);\n" +
+ " ps.executeUpdate();\n" +
+ " ...\n" +
+ " case \"trigger\":\n" +
+ " // 第二步:先通过ID取出已存储的username。\n" +
+ " String storedUsername = queryUsernameById(id);\n" +
+ " // 漏洞点:数据库中的历史数据再次被拼接进SQL结构。\n" +
+ " String vulSql = \"SELECT id, username, password FROM sqli WHERE username = '\" + storedUsername + \"'\";\n" +
+ " ResultSet rs = stmt.executeQuery(vulSql);\n" +
+ " ...\n" +
+ " case \"safeTrigger\":\n" +
+ " String safeSql = \"SELECT id, username, password FROM sqli WHERE username = ?\";\n" +
+ " PreparedStatement safePs = conn.prepareStatement(safeSql);\n" +
+ " safePs.setString(1, storedUsername);\n" +
+ " ResultSet safeRs = safePs.executeQuery();\n" +
+ " ...\n" +
+ " }\n" +
+ "}\n"
+const special5Union = "// UNION回显要求原查询与联合查询列数一致、类型兼容。\n" +
+ "public R special5Union(String type,String id) {\n" +
+ " switch (type) {\n" +
+ " case \"raw\":\n" +
+ " String sql = \"SELECT id, username, password FROM sqli WHERE id = \" + id;\n" +
+ " // 示例:id = -1 UNION SELECT 1,database(),user()\n" +
+ " ResultSet rs = stmt.executeQuery(sql);\n" +
+ " ...\n" +
+ " case \"prepareStatement\":\n" +
+ " String safeSql = \"SELECT id, username, password FROM sqli WHERE id = ?\";\n" +
+ " PreparedStatement ps = conn.prepareStatement(safeSql);\n" +
+ " ps.setString(1, id);\n" +
+ " ResultSet safeRs = ps.executeQuery();\n" +
+ " ...\n" +
+ " }\n" +
+ "}\n"
// MyBatis
const vul1CustomMethod = "vul1CustomMethod"
@@ -582,6 +700,9 @@ const mybatisSpecial1OrderBy =
" sqlis = sqliService.orderByPrepareStatement(field);\n" +
" break;\n" +
" case \"writeList\":\n" +
+ " if (!checkUserInput.checkSqlWhiteList(field)) {\n" +
+ " return R.error(\"field字段不合法!\");\n" +
+ " }\n" +
" sqlis = sqliService.orderByWriteList(field);\n" +
" ...\n" +
"// Service层\n" +
@@ -599,21 +720,21 @@ const mybatisSpecial1OrderBy =
" return sqliMapper.orderByWriteList(field);\n" +
"}\n" +
"// Mapper层\n" +
- "\n" +
+ "\n" +
"\n" +
" SELECT * FROM sqli\n" +
" \n" +
" ORDER BY ${field}\n" +
" \n" +
" \n" +
- "\n" +
+ "\n" +
"\n" +
" SELECT * FROM sqli\n" +
" \n" +
" ORDER BY #{field}\n" +
" \n" +
" \n" +
- "\n" +
+ "\n" +
"\n" +
" SELECT * FROM sqli\n" +
" \n" +
@@ -671,8 +792,11 @@ const mybatisSpecial3In = "// Controller层\n" +
" sqlis = sqliService.inPrepareStatement(scope);\n" +
" break;\n" +
" case \"Foreach\":\n" +
- "\n" +
- " sqlis = sqliService.inSafeForeach(parseInputToList(scope));\n" +
+ " List idList = parseInputToList(scope);\n" +
+ " if (idList.isEmpty()) {\n" +
+ " return R.error(\"scope中没有合法整数ID!\");\n" +
+ " }\n" +
+ " sqlis = sqliService.inSafeForeach(idList);\n" +
" break;\n" +
" ...\n" +
"// Service层\n" +
@@ -724,18 +848,153 @@ const anyFileUploadCode = "// 原生漏洞场景,未做任何限制\n" +
"}\n" +
"// uploadFile方法详见文件上传导致XSS模块\n"
const anyFileUploadWhiteCode = "// 检测文件后缀,做白名单过滤\n" +
+ "String suffix = FilenameUtils.getExtension(file.getOriginalFilename());\n" +
"if (!checkUserInput.checkFileSuffixWhiteList(suffix)){\n" +
" return R.error(\"只能上传图片哦!\");\n" +
"}\n" +
+ "if (!isAllowedImageContent(file, suffix)) {\n" +
+ " return R.error(\"文件内容与图片类型不匹配!\");\n" +
+ "}\n" +
"\n" +
"public boolean checkFileSuffixWhiteList(String suffix) {\n" +
+ " if (suffix == null || suffix.isEmpty()) {\n" +
+ " return false;\n" +
+ " }\n" +
" String[] white_list = {\"jpg\", \"png\", \"gif\",\"jpeg\",\"bmp\",\"ico\"};\n" +
" for (String s : white_list) {\n" +
- " if (suffix.toLowerCase().contains(s)) {\n" +
+ " if (suffix.equalsIgnoreCase(s)) {\n" +
" return true;\n" +
" }\n" +
" }\n" +
" return false;\n" +
+ "}\n" +
+ "\n" +
+ "private boolean isAllowedImageContent(MultipartFile file, String suffix) throws IOException {\n" +
+ " if (\"ico\".equalsIgnoreCase(suffix)) {\n" +
+ " // 校验 ICO 文件头:00 00 01 00\n" +
+ " }\n" +
+ " BufferedImage image = ImageIO.read(file.getInputStream());\n" +
+ " return image != null;\n" +
+ " // ImageIO 解析异常时返回 false,避免损坏图片导致 500\n" +
+ "}"
+
+const vul1Native = "public R vul1(@RequestParam String username) {\n" +
+ " try {\n" +
+ " String sql = \"SELECT * FROM sqli WHERE username = '\" + username + \"'\";\n" +
+ " Object[] result = (Object[]) hibernateTemplate.execute(session ->\n" +
+ " session.createNativeQuery(sql).uniqueResult()\n" +
+ " );\n" +
+ " message = \"查询成功,用户名:\" + result[1] + \" 密码:\" +result[2];\n" +
+ " return R.ok(message);\n" +
+ " } catch (Exception e) {\n" +
+ " log.error(\"查询失败\", e);\n" +
+ " return R.error(e.getMessage());\n" +
+ " }\n" +
+ "}"
+const vul2Hql = "public R vul2(@RequestParam String username) {\n" +
+ " try {\n" +
+ " String hql = \"FROM Sqli WHERE username = '\" + username + \"'\";\n" +
+ " Sqli result = (Sqli) hibernateTemplate.execute(session ->\n" +
+ " session.createQuery(hql).uniqueResult()\n" +
+ " );\n" +
+ " message = \"查询成功,用户名:\" +result.getUsername()+ \" 密码:\" +result.getPassword();\n" +
+ " return R.ok(message);\n" +
+ " } catch (Exception e) {\n" +
+ " log.error(\"查询失败\", e);\n" +
+ " return R.error(e.getMessage());\n" +
+ " }\n" +
+ "}"
+const safe1Param = "public R safe(@RequestParam String username) {\n" +
+ " try {\n" +
+ " String hql = \"FROM Sqli WHERE username = :username\";\n" +
+ " Sqli result = hibernateTemplate.execute(session ->\n" +
+ " (Sqli) session.createQuery(hql)\n" +
+ " .setParameter(\"username\", username)\n" +
+ " .uniqueResult()\n" +
+ " );\n" +
+ " message = \"查询成功,用户名:\" +result.getUsername()+ \" 密码:\" +result.getPassword();\n" +
+ " return R.ok(message);\n" +
+ " } catch (Exception e) {\n" +
+ " log.error(\"查询失败\", e);\n" +
+ " return R.error(e.getMessage());\n" +
+ " }\n" +
+ "}"
+
+const vul1JpaJpql = "public R vul1(@RequestParam String username) {\n" +
+ " try {\n" +
+ " String jpql = \"SELECT s FROM Sqli s WHERE s.username = '\" + username + \"'\";\n" +
+ " Query query = entityManager.createQuery(jpql);\n" +
+ " List results = query.getResultList();\n" +
+ " if (results == null || results.isEmpty()) {\n" +
+ " return R.error(\"未找到记录\");\n" +
+ " }\n" +
+ " StringBuilder sb = new StringBuilder();\n" +
+ " sb.append(\"查询成功,找到 \").append(results.size()).append(\" 条记录\\n\");\n" +
+ " message = sb.toString();\n" +
+ " log.info(message);\n" +
+ " return R.ok(message);\n" +
+ " } catch (Exception e) {\n" +
+ " String errorMsg = e.getMessage();\n" +
+ " log.error(\"查询失败: {}\", errorMsg, e);\n" +
+ " return R.error(errorMsg);\n" +
+ " }\n" +
+ "}"
+const vul2JpaSort = "public R vul2(@RequestParam String orderBy) {\n" +
+ " try {\n" +
+ " String jpql = \"SELECT s FROM Sqli s ORDER BY s.\" + orderBy;\n" +
+ " Query query = entityManager.createQuery(jpql);\n" +
+ " List results = query.getResultList();\n" +
+ " return R.ok(formatResults(results));\n" +
+ " } catch (Exception e) {\n" +
+ " String errorMsg = e.getMessage();\n" +
+ " log.error(\"查询失败: {}\", errorMsg, e);\n" +
+ " return R.error(errorMsg);\n" +
+ " }\n" +
+ "}"
+const safeJpaParam = "public R safe(@RequestParam String username) {\n" +
+ " try {\n" +
+ " String jpql = \"SELECT s FROM Sqli s WHERE s.username = :username\";\n" +
+ " Query query = entityManager.createQuery(jpql)\n" +
+ " .setParameter(\"username\", username);\n" +
+ " List results = query.getResultList();\n" +
+ " if (results == null || results.isEmpty()) {\n" +
+ " return R.error(\"未找到记录\");\n" +
+ " }\n" +
+ " StringBuilder sb = new StringBuilder();\n" +
+ " sb.append(\"查询成功,找到 \").append(results.size()).append(\" 条记录\\n\");\n" +
+ " message = sb.toString();\n" +
+ " log.info(message);\n" +
+ " return R.ok(message);\n" +
+ " } catch (Exception e) {\n" +
+ " String errorMsg = e.getMessage();\n" +
+ " log.error(\"查询失败: {}\", errorMsg, e);\n" +
+ " return R.error(errorMsg);\n" +
+ " }\n" +
+ "}"
+const safeJpaSort = "public R safeOrder(@RequestParam String orderBy) {\n" +
+ " try {\n" +
+ " Map orderByMap = new HashMap<>();\n" +
+ " orderByMap.put(\"id\", \"id\");\n" +
+ " orderByMap.put(\"username\", \"username\");\n" +
+ " orderByMap.put(\"password\", \"password\");\n" +
+ "\n" +
+ " String safeOrderBy = orderByMap.get(orderBy);\n" +
+ " if (safeOrderBy == null) {\n" +
+ " return R.error(\"排序字段不合法\");\n" +
+ " }\n" +
+ "\n" +
+ " CriteriaBuilder cb = entityManager.getCriteriaBuilder();\n" +
+ " CriteriaQuery cq = cb.createQuery(Sqli.class);\n" +
+ " Root root = cq.from(Sqli.class);\n" +
+ " cq.select(root).orderBy(cb.asc(root.get(safeOrderBy)));\n" +
+ "\n" +
+ " List results = entityManager.createQuery(cq).getResultList();\n" +
+ " return R.ok(formatResults(results));\n" +
+ " } catch (Exception e) {\n" +
+ " String errorMsg = e.getMessage();\n" +
+ " log.error(\"查询失败: {}\", errorMsg, e);\n" +
+ " return R.error(errorMsg);\n" +
+ " }\n" +
"}"
// 任意文件类型-文件删除
@@ -753,12 +1012,19 @@ const deleteFile = "public String vul(String filePath) {\n" +
" }\n" +
"}"
const safeDeleteFile = "public String safe(String fileName) {\n" +
- " // 限制删除文件所在目录为 /static/upload/下\n" +
- " String baseDir = sysConstant.getUploadFolder(); \n" +
- " File file = new File(baseDir, fileName);\n" +
+ " String baseDir = sysConstant.getUploadFolder();\n" +
+ " Path basePath = Paths.get(baseDir).toRealPath();\n" +
+ " Path filePath = basePath.resolve(fileName).normalize();\n" +
+ " if (!filePath.startsWith(basePath)) {\n" +
+ " return \"访问被拒绝:文件路径不合法\";\n" +
+ " }\n" +
" boolean deleted = false;\n" +
- " if (file.exists() && file.getCanonicalPath().startsWith(new File(baseDir).getCanonicalPath())) {\n" +
- " deleted = file.delete();\n" +
+ " if (Files.isRegularFile(filePath)) {\n" +
+ " Path realFilePath = filePath.toRealPath();\n" +
+ " if (!realFilePath.startsWith(basePath)) {\n" +
+ " return \"访问被拒绝:文件真实路径不合法\";\n" +
+ " }\n" +
+ " deleted = Files.deleteIfExists(filePath);\n" +
" }\n" +
" if (deleted) {\n" +
" return \"文件删除成功: \" + fileName;\n" +
@@ -775,7 +1041,7 @@ const readFile = "public String vul(String fileName) throws IOException {\n" +
" if (file.exists() && file.isFile()) {\n" +
" Path filePath = file.toPath();\n" +
" // 使用 BufferedReader 和流 API 逐行读取文件\n" +
- " try (var lines = Files.lines(filePath)) {\n" +
+ " try (Stream lines = Files.lines(filePath)) {\n" +
" return lines\n" +
" .map(line -> line + \" \")\n" +
" .collect(Collectors.joining());\n" +
@@ -784,15 +1050,19 @@ const readFile = "public String vul(String fileName) throws IOException {\n" +
" return \"当前路径:\"+currentPath+\" 文件不存在或路径不正确:\" + fileName;\n" +
" }"
const safeReadFile = "public String safe(String fileName) throws IOException {\n" +
- " String baseDir = sysConstant.getUploadFolder(); \n" +
- " Path filePath = Paths.get(baseDir, fileName).normalize(); \n" +
- " // 确保文件路径在允许的目录中\n" +
- " if (!filePath.startsWith(Paths.get(baseDir))) {\n" +
+ " String baseDir = sysConstant.getUploadFolder();\n" +
+ " Path basePath = Paths.get(baseDir).toRealPath();\n" +
+ " Path filePath = basePath.resolve(fileName).normalize();\n" +
+ " // 先标准化路径,再确认目标文件仍位于允许目录内\n" +
+ " if (!filePath.startsWith(basePath)) {\n" +
" return \"访问被拒绝:文件路径不合法\";\n" +
" }\n" +
- " File file = filePath.toFile();\n" +
- " if (file.exists() && file.isFile()) {\n" +
- " return new String(Files.readAllBytes(file.toPath()));\n" +
+ " if (Files.isRegularFile(filePath)) {\n" +
+ " Path realFilePath = filePath.toRealPath();\n" +
+ " if (!realFilePath.startsWith(basePath)) {\n" +
+ " return \"访问被拒绝:文件真实路径不合法\";\n" +
+ " }\n" +
+ " return new String(Files.readAllBytes(realFilePath));\n" +
" } else {\n" +
" return \"文件不存在或路径不正确:\" + fileName;\n" +
" }\n" +
@@ -819,13 +1089,19 @@ const safeDownloadFile = 'public void safe(String fileName,HttpServletResponse r
' if (!isValidFileName(fileName)) {\n' +
' response.sendError(HttpServletResponse.SC_BAD_REQUEST, "非法文件名:" + fileName);\n' +
' return;\n' +
- ' }\n' +
- ' File file = new File(baseDir, fileName);\n' +
+ ' }\n' +
+ ' Path basePath = Paths.get(baseDir).toRealPath();\n' +
+ ' Path filePath = basePath.resolve(fileName).normalize();\n' +
'\n' +
- ' if (file.exists() && file.isFile()) {\n' +
+ ' if (filePath.startsWith(basePath) && Files.isRegularFile(filePath)) {\n' +
+ ' Path realFilePath = filePath.toRealPath();\n' +
+ ' if (!realFilePath.startsWith(basePath)) {\n' +
+ ' response.sendError(HttpServletResponse.SC_FORBIDDEN, "文件真实路径不合法:" + fileName);\n' +
+ ' return;\n' +
+ ' }\n' +
' response.setContentType("application/octet-stream");\n' +
- ' response.setHeader("Content-Disposition", "attachment; filename=\\"" + file.getName() + "\\"");\n' +
- ' try (FileInputStream fis = new FileInputStream(file);\n' +
+ ' response.setHeader("Content-Disposition", "attachment; filename=\\"" + realFilePath.getFileName().toString() + "\\"");\n' +
+ ' try (InputStream fis = Files.newInputStream(realFilePath);\n' +
' OutputStream os = response.getOutputStream()) {\n' +
' StreamUtils.copy(fis, os);\n' +
' os.flush();\n' +
@@ -836,10 +1112,20 @@ const safeDownloadFile = 'public void safe(String fileName,HttpServletResponse r
'}'
// ssrf-服务端请求伪造
-const vul1URLConnection = "public String vul(String url) {\n" +
+const vul1URLConnection = "@GetMapping(\"/internal/metadata\")\n" +
+ "public String internalMetadata() {\n" +
+ " return \"instance-id: i-javaseclab-ssrf ...\";\n" +
+ "}\n" +
+ "\n" +
+ "@GetMapping(\"/redirect\")\n" +
+ "public void redirect(String target, HttpServletResponse response) throws IOException {\n" +
+ " response.sendRedirect(target);\n" +
+ "}\n" +
+ "\n" +
+ "public String vul(String url) {\n" +
" try {\n" +
" URL u = new URL(url);\n" +
- " // 这里以URLConnection作为演示\n" +
+ " // URLConnection默认可请求file/http等协议,HTTP请求还可能自动跟随跳转\n" +
" URLConnection conn = u.openConnection();\n" +
" BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));\n" +
" String content;\n" +
@@ -861,24 +1147,53 @@ const safe1WhiteList = "public String safe(String url) {\n" +
" } else if (!checkUserInput.ssrfWhiteList(url)) {\n" +
" return \"非白名单域名!\";\n" +
" } else {\n" +
+ " URL u = new URL(url);\n" +
+ " HttpURLConnection conn = (HttpURLConnection) u.openConnection();\n" +
+ " // 禁止自动跳转,每一跳都应重新校验协议、域名和IP\n" +
+ " conn.setInstanceFollowRedirects(false);\n" +
+ " conn.setConnectTimeout(3000);\n" +
+ " conn.setReadTimeout(3000);\n" +
" ...\n" +
" }\n" +
"}\n" +
- "// ssrf:判断http(s)协议\n" +
+ "// SSRF:判断http(s)协议,避免 startsWith 被空白、大小写、畸形URL等绕过\n" +
"public boolean isHttp(String url){\n" +
- " return url.startsWith(\"http://\") || url.startsWith(\"https://\");\n" +
+ " try {\n" +
+ " URI uri = new URI(url);\n" +
+ " String scheme = uri.getScheme();\n" +
+ " return \"http\".equalsIgnoreCase(scheme) || \"https\".equalsIgnoreCase(scheme);\n" +
+ " } catch (URISyntaxException e) {\n" +
+ " return false;\n" +
+ " }\n" +
"}\n" +
- "// ssrf:请求域名白名单\n" +
+ "// SSRF:请求域名白名单,同时校验解析后的IP\n" +
"public boolean ssrfWhiteList(String url) {\n" +
" List urlList = new ArrayList<>(Arrays.asList(\"baidu.com\", \"www.baidu.com\", \"whgojp.top\"));\n" +
" try {\n" +
- " URI uri = new URI(url.toLowerCase());\n" +
+ " URI uri = new URI(url);\n" +
" String host = uri.getHost();\n" +
- " return urlList.contains(host);\n" +
- " } catch (URISyntaxException e) {\n" +
+ " if (host == null || uri.getUserInfo() != null) {\n" +
+ " return false;\n" +
+ " }\n" +
+ " return urlList.contains(host.toLowerCase(Locale.ROOT)) && !isInternalHost(host);\n" +
+ " } catch (URISyntaxException | UnknownHostException e) {\n" +
" System.out.println(e);\n" +
" return false;\n" +
" }\n" +
+ "}\n" +
+ "\n" +
+ "private boolean isInternalHost(String host) throws UnknownHostException {\n" +
+ " InetAddress[] addresses = InetAddress.getAllByName(host);\n" +
+ " for (InetAddress address : addresses) {\n" +
+ " if (address.isAnyLocalAddress()\n" +
+ " || address.isLoopbackAddress()\n" +
+ " || address.isLinkLocalAddress()\n" +
+ " || address.isSiteLocalAddress()\n" +
+ " || address.isMulticastAddress()) {\n" +
+ " return true;\n" +
+ " }\n" +
+ " }\n" +
+ " return false;\n" +
"}"
// RCE
@@ -928,13 +1243,33 @@ const vulProcessImpl = "public R vul3(String payload) throws Exception {\n" +
" return R.ok(output.toString());\n" +
" }\n" +
"}"
-const safeProcessBuilder = "// 验证命令是否在允许的列表中\n" +
- "if (!ALLOWED_COMMANDS.contains(payload)) {\n" +
- " return R.error(\"不允许执行该命令!\");\n" +
+const safeProcessBuilder = "// 业务动作到固定命令参数的映射,用户不能直接控制命令字符串\n" +
+ "private static final Map> ALLOWED_COMMANDS = new HashMap<>();\n" +
+ "static {\n" +
+ " ALLOWED_COMMANDS.put(\"list\", Arrays.asList(\"ls\"));\n" +
+ " ALLOWED_COMMANDS.put(\"date\", Arrays.asList(\"date\"));\n" +
"}\n" +
"\n" +
- "// 可执行命令白名单\n" +
- "private static final List ALLOWED_COMMANDS = Arrays.asList(\"ls\", \"date\");"
+ "public R safe(String payload) throws IOException {\n" +
+ " List command = ALLOWED_COMMANDS.get(payload);\n" +
+ " if (command == null) {\n" +
+ " return R.error(\"不允许执行该动作!\");\n" +
+ " }\n" +
+ " ProcessBuilder pb = new ProcessBuilder(command);\n" +
+ " pb.redirectErrorStream(true);\n" +
+ " Process process = pb.start();\n" +
+ " try {\n" +
+ " if (!process.waitFor(3, TimeUnit.SECONDS)) {\n" +
+ " process.destroyForcibly();\n" +
+ " return R.error(\"命令执行超时!\");\n" +
+ " }\n" +
+ " } catch (InterruptedException e) {\n" +
+ " Thread.currentThread().interrupt();\n" +
+ " return R.error(\"命令执行被中断!\");\n" +
+ " }\n" +
+ " String output = readProcessOutput(process);\n" +
+ " return R.ok(output);\n" +
+ "}"
const vulGroovy = "public R vulGroovy(String payload) {\n" +
" try {\n" +
@@ -964,30 +1299,16 @@ const vulGroovy = "public R vulGroovy(String payload) {\n" +
" return output.toString();\n" +
"}"
const safeGroovy = 'public R safeGroovy(String payload) {\n' +
- ' List trustedScripts = Arrays.asList(\n' +
- ' "\\"id\\".execute()",\n' +
- ' "\\"ls\\".execute()",\n' +
- ' "\\"whoami\\".execute()"\n' +
- ' );\n' +
- ' if (!isTrustedScript(payload, trustedScripts)) {\n' +
- ' return R.error("非法的脚本输入!");\n' +
+ ' if ("hello".equals(payload)) {\n' +
+ ' return R.ok("[+] 受控动作执行结果:Hello JavaSecLab");\n' +
' }\n' +
- ' try {\n' +
- ' GroovyShell shell = new GroovyShell();\n' +
- ' Object result = shell.evaluate(payload); \n' +
- ' if (result instanceof Process) {\n' +
- ' Process process = (Process) result;\n' +
- ' String output = getProcessOutput(process);\n' +
- ' return R.ok("[+] 执行受信任的脚本,结果:" + output);\n' +
- ' } else {\n' +
- ' return R.ok("[+] 执行受信任的脚本,结果:" + result.toString());\n' +
- ' }\n' +
- ' } catch (Exception e) {\n' +
- ' return R.error(e.getMessage());\n' +
+ ' if ("time".equals(payload)) {\n' +
+ ' return R.ok("[+] 受控动作执行结果:" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));\n' +
' }\n' +
- '}\n' +
- 'private boolean isTrustedScript(String script, List trustedScripts) {\n' +
- ' return trustedScripts.contains(script);\n' +
+ ' if ("sum".equals(payload)) {\n' +
+ ' return R.ok("[+] 受控动作执行结果:" + (1 + 2 + 3));\n' +
+ ' }\n' +
+ ' return R.error("非法的动作输入!");\n' +
'}'
// XXE
@@ -1026,6 +1347,17 @@ const vulSAXParser = "public String vul2(String payload) {\n" +
" }\n" +
"}"
+const vulDocumentBuilder = "public String vul3(String payload) {\n" +
+ " try {\n" +
+ " DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n" +
+ " DocumentBuilder builder = factory.newDocumentBuilder();\n" +
+ " Document document = builder.parse(new InputSource(new StringReader(payload)));\n" +
+ " return document.getDocumentElement().getTextContent();\n" +
+ " } catch (Exception e) {\n" +
+ " return e.toString();\n" +
+ " }\n" +
+ "}"
+
const safeXMLReader = "public String safe1(String payload) {\n" +
" try {\n" +
" XMLReader xmlReader = XMLReaderFactory.createXMLReader();\n" +
@@ -1033,6 +1365,8 @@ const safeXMLReader = "public String safe1(String payload) {\n" +
" xmlReader.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", true);\n" +
" xmlReader.setFeature(\"http://xml.org/sax/features/external-general-entities\", false);\n" +
" xmlReader.setFeature(\"http://xml.org/sax/features/external-parameter-entities\", false);\n" +
+ " xmlReader.setFeature(\"http://apache.org/xml/features/nonvalidating/load-external-dtd\", false);\n" +
+ " xmlReader.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader(\"\")));\n" +
" ...\n" +
" xmlReader.parse(new InputSource(new StringReader(payload)));\n" +
" return stringWriter.toString();\n" +
@@ -1040,7 +1374,32 @@ const safeXMLReader = "public String safe1(String payload) {\n" +
" return e.getMessage();\n" +
" }\n" +
"}"
-const safeBlackList = "public String safe2(String payload) {\n" +
+const safeDocumentBuilder = "public String safe3(String payload) {\n" +
+ " try {\n" +
+ " DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n" +
+ " factory.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", true);\n" +
+ " factory.setFeature(\"http://xml.org/sax/features/external-general-entities\", false);\n" +
+ " factory.setFeature(\"http://xml.org/sax/features/external-parameter-entities\", false);\n" +
+ " factory.setFeature(\"http://apache.org/xml/features/nonvalidating/load-external-dtd\", false);\n" +
+ " factory.setXIncludeAware(false);\n" +
+ " factory.setExpandEntityReferences(false);\n" +
+ " setAttributeIfSupported(factory, XMLConstants.ACCESS_EXTERNAL_DTD, \"\");\n" +
+ " setAttributeIfSupported(factory, XMLConstants.ACCESS_EXTERNAL_SCHEMA, \"\");\n" +
+ " DocumentBuilder builder = factory.newDocumentBuilder();\n" +
+ " builder.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader(\"\")));\n" +
+ " ...\n" +
+ " } catch (Exception e) {\n" +
+ " return e.toString();\n" +
+ " }\n" +
+ "}\n" +
+ "private void setAttributeIfSupported(DocumentBuilderFactory factory, String name, String value) {\n" +
+ " try {\n" +
+ " factory.setAttribute(name, value);\n" +
+ " } catch (IllegalArgumentException ignored) {\n" +
+ " }\n" +
+ "}"
+const safeBlackList = "// 黑名单只能作为辅助检测,不应替代解析器安全配置\n" +
+ "public String safe2(String payload) {\n" +
" String[] black_list = {\"ENTITY\", \"DOCTYPE\"};\n" +
" for (String keyword : black_list) {\n" +
" if (payload.toUpperCase().contains(keyword)) {\n" +
@@ -1164,7 +1523,7 @@ const safeHorizon = "public R safe(String username){\n" +
" // 获取当前登录的用户名\n" +
" String currentUsername = SecurityContextHolder.getContext().getAuthentication().getName();\n" +
" // 检查当前请求的用户名是否和登录用户名一致\n" +
- " if (!username.equals(currentUsername)) {\n" +
+ " if (username == null || !username.equals(currentUsername)) {\n" +
" return R.error(\"您没有权限查看该用户的资料,当前登录用户:\"+currentUsername);\n" +
" }\n" +
" // 查询用户信息\n" +
@@ -1175,9 +1534,158 @@ const safeHorizon = "public R safe(String username){\n" +
" return R.error(\"用户名不存在\");\n" +
" }\n" +
"}"
+const vulVertical = "public String vul() {\n" +
+ " // 漏洞点:只要知道管理员功能地址即可直接访问,没有做服务端角色校验。\n" +
+ " return \"vul/logic/idor/admin\";\n" +
+ "}"
// 支付漏洞
+const vul1Pay = "public R vul1(@RequestParam String count, @RequestParam String price) {\n" +
+ " try {\n" +
+ " double totalPrice = Integer.parseInt(count) * Double.parseDouble(price);\n" +
+ " log.info(\"用户需支付金额:\" + totalPrice);\n" +
+ " \n" +
+ " // 直接使用客户端传入的价格,未与服务端商品实际价格进行校验\n" +
+ " BigDecimal currentMoney = userMoney.get();\n" +
+ " if (currentMoney.compareTo(BigDecimal.valueOf(totalPrice)) < 0) {\n" +
+ " return R.error(\"支付金额不足,支付失败!\");\n" +
+ " }\n" +
+ " userMoney.set(currentMoney.subtract(BigDecimal.valueOf(totalPrice)));\n" +
+ " return R.ok(\"支付成功!剩余余额:\" + userMoney.get());\n" +
+ " } catch (Exception e) {\n" +
+ " return R.error(e.toString());\n" +
+ " }\n" +
+ "}";
+
+const vul2Pay = "public R vul2(@RequestParam String orderId, @RequestParam double amount) {\n" +
+ " // 未检查订单是否已支付\n" +
+ " // 这里应该使用paymentStatusMap检查订单是否已支付,但为了演示漏洞,故意不检查\n" +
+ " BigDecimal currentMoney = userMoney.get();\n" +
+ " if (currentMoney.compareTo(BigDecimal.valueOf(amount)) < 0) {\n" +
+ " return R.error(\"余额不足\");\n" +
+ " }\n" +
+ " userMoney.set(currentMoney.subtract(BigDecimal.valueOf(amount)));\n" +
+ " return R.ok(\"支付成功!剩余余额:\" + userMoney.get());\n" +
+ "}";
+const vul3Pay = "public R vul3(@RequestParam String orderId, @RequestParam double amount) {\n" +
+ " // 模拟处理延迟\n" +
+ " try {\n" +
+ " Thread.sleep(1000);\n" +
+ " } catch (InterruptedException e) {\n" +
+ " Thread.currentThread().interrupt();\n" +
+ " }\n" +
+ "\n" +
+ " BigDecimal currentMoney = userMoney.get();\n" +
+ " if (currentMoney.compareTo(BigDecimal.valueOf(amount)) < 0) {\n" +
+ " return R.error(\"余额不足\");\n" +
+ " }\n" +
+ " userMoney.set(currentMoney.subtract(BigDecimal.valueOf(amount)));\n" +
+ " return R.ok(\"支付成功!剩余余额:\" + userMoney.get());\n" +
+ "}";
+
+const vulConcurrent = "public R vul(@RequestParam String orderId, @RequestParam double amount) {\n" +
+ " // 模拟业务处理耗时,扩大并发窗口\n" +
+ " Thread.sleep(1000);\n" +
+ "\n" +
+ " BigDecimal currentMoney = userMoney.get();\n" +
+ " BigDecimal payAmount = BigDecimal.valueOf(amount);\n" +
+ " if (currentMoney.compareTo(payAmount) < 0) {\n" +
+ " return R.error(\"余额不足\");\n" +
+ " }\n" +
+ " // 漏洞点:读取余额和写回余额不是一个原子操作,相同订单也没有幂等校验\n" +
+ " userMoney.set(currentMoney.subtract(payAmount));\n" +
+ " return R.ok(\"支付成功!订单:\" + orderId + \",剩余余额:\" + userMoney.get());\n" +
+ "}";
+
+const safeConcurrent = "public R safe(@RequestParam String orderId, @RequestParam double amount) {\n" +
+ " BigDecimal payAmount = BigDecimal.valueOf(amount);\n" +
+ " synchronized (paymentLock) {\n" +
+ " if (paidOrders.contains(orderId)) {\n" +
+ " return R.error(\"订单已支付,拒绝重复扣款:\" + orderId);\n" +
+ " }\n" +
+ " BigDecimal currentMoney = userMoney.get();\n" +
+ " if (currentMoney.compareTo(payAmount) < 0) {\n" +
+ " return R.error(\"余额不足\");\n" +
+ " }\n" +
+ " paidOrders.add(orderId);\n" +
+ " userMoney.set(currentMoney.subtract(payAmount));\n" +
+ " return R.ok(\"支付成功!订单:\" + orderId + \",剩余余额:\" + userMoney.get());\n" +
+ " }\n" +
+ "}";
+
+const vul4Pay = "@ApiOperation(\"支付流程绕过漏洞 - 创建订单\")\n" +
+ "@RequestMapping(\"/vul4/create\")\n" +
+ "public R createOrder(@RequestParam String orderId, @RequestParam double amount) {\n" +
+ " OrderStatus status = new OrderStatus(orderId, BigDecimal.valueOf(amount));\n" +
+ " orderStatusMap.put(orderId, status);\n" +
+ " Map data = new HashMap<>();\n" +
+ " data.put(\"orderId\", orderId);\n" +
+ " data.put(\"amount\", amount);\n" +
+ " return R.ok(\"订单创建成功\").put(\"data\", data);\n" +
+ "}\n" +
+ "\n" +
+ "@ApiOperation(\"支付流程绕过漏洞 - 查询订单状态\")\n" +
+ "@RequestMapping(\"/vul4/status\")\n" +
+ "public R getOrderStatus(@RequestParam String orderId) {\n" +
+ " OrderStatus status = orderStatusMap.get(orderId);\n" +
+ " if (status == null) {\n" +
+ " return R.error(\"订单不存在\");\n" +
+ " }\n" +
+ " Map data = new HashMap<>();\n" +
+ " data.put(\"orderId\", status.orderId);\n" +
+ " data.put(\"amount\", status.amount);\n" +
+ " data.put(\"isPaid\", status.isPaid);\n" +
+ " return R.ok().put(\"data\", data);\n" +
+ "}\n" +
+ "\n" +
+ "@ApiOperation(\"支付流程绕过漏洞 - 支付通知\")\n" +
+ "@RequestMapping(\"/vul4/notify\")\n" +
+ "public R paymentNotify(@RequestParam String orderId, @RequestParam boolean success) {\n" +
+ " // 未验证通知来源,直接更新订单状态\n" +
+ " OrderStatus status = orderStatusMap.get(orderId);\n" +
+ " if (status == null) {\n" +
+ " return R.error(\"订单不存在\");\n" +
+ " }\n" +
+ " status.isPaid = success;\n" +
+ " return R.ok(\"状态更新成功\");\n" +
+ "}";
+const vul5Pay = "public R integerOverflow(@RequestParam String count, @RequestParam String price) {\n" +
+ " try {\n" +
+ " Integer countValue = Integer.valueOf(count);\n" +
+ " Integer priceValue = Integer.valueOf(price);\n" +
+ "\n" +
+ " // 整数溢出场景:当 count 或 price 数值过大时,可能会导致溢出\n" +
+ " int totalAmount = countValue * priceValue;\n" +
+ " log.info(\"用户需支付金额:\" + totalAmount);\n" +
+ "\n" +
+ " BigDecimal currentMoney = userMoney.get();\n" +
+ " if (currentMoney.compareTo(BigDecimal.valueOf(totalAmount)) < 0) {\n" +
+ " return R.error(\"支付金额不足,支付失败!\");\n" +
+ " }\n" +
+ " userMoney.set(currentMoney.subtract(BigDecimal.valueOf(totalAmount)));\n" +
+ " return R.ok(\"支付成功!剩余余额:\" + userMoney.get());\n" +
+ " } catch (Exception e) {\n" +
+ " return R.error(\"无效的输入,请输入有效的数量和价格!\");\n" +
+ " }\n" +
+ "}";
+const vul6Pay = "public R floatingPointPrecision(@RequestParam String count, @RequestParam String price) {\n" +
+ " try {\n" +
+ " double totalAmount = Double.parseDouble(count) * Double.parseDouble(price);\n" +
+ " // 漏洞点:把二进制浮点计算结果直接转成金额,可能引入精度误差\n" +
+ " BigDecimal amountValue = new BigDecimal(totalAmount);\n" +
+ " log.info(\"用户需支付金额:\" + amountValue);\n" +
+ "\n" +
+ " BigDecimal currentMoney = userMoney.get();\n" +
+ " if (currentMoney.compareTo(amountValue) < 0) {\n" +
+ " return R.error(\"支付金额不足,支付失败!\");\n" +
+ " }\n" +
+ " userMoney.set(currentMoney.subtract(amountValue));\n" +
+ " return R.ok(\"支付成功!实际扣款金额:\" + amountValue + \",剩余余额:\" + userMoney.get());\n" +
+ " } catch (Exception e) {\n" +
+ " return R.error(\"无效的输入,请输入有效的数量和价格!\");\n" +
+ " }\n" +
+ "}";
// 其他漏洞
const vul1SpringMvcRedirect = "// 基于Spring MVC的重定向方式\n" +
@@ -1280,17 +1788,31 @@ const vulXffforgery = "public String vul1(HttpServletRequest request, Model mode
"}";
const safeXffforgery = "public String safe(HttpServletRequest request, HttpServletResponse response, Model model, String xff){\n" +
- " ...\n" +
- " if (!isTrustedProxy(remoteHost)){\n" +
- " model.addAttribute(\"clientIP\", request.getRemoteAddr());\n" +
- " model.addAttribute(\"sensitiveInfo\", \"源ip不在白名单范围内!\");\n" +
+ " String proxyIp = request.getRemoteAddr();\n" +
+ " String remoteHost = proxyIp;\n" +
+ " if (\"true\".equals(xff)) {\n" +
+ " if (!isTrustedProxy(proxyIp)){\n" +
+ " model.addAttribute(\"clientIP\", proxyIp);\n" +
+ " model.addAttribute(\"sensitiveInfo\", \"非可信代理来源,忽略XFF头:\" + proxyIp);\n" +
+ " return \"vul/other/onlyForGoogle\";\n" +
+ " }\n" +
+ " remoteHost = getFirstForwardedIp(request.getHeader(\"X-Forwarded-For\"));\n" +
+ " }\n" +
+ " if (remoteHost == null || remoteHost.isEmpty()) {\n" +
+ " model.addAttribute(\"clientIP\", proxyIp);\n" +
+ " model.addAttribute(\"sensitiveInfo\", \"XFF头为空或格式异常!\");\n" +
" return \"vul/other/onlyForGoogle\";\n" +
" }\n" +
- " ...\n" +
+ " boolean isClientIP8888 = \"8.8.8.8\".equals(remoteHost);\n" +
+ " model.addAttribute(\"clientIP\", remoteHost);\n" +
+ " if (isClientIP8888) {\n" +
+ " model.addAttribute(\"sensitiveInfo\", \"username:admin,password:Admin123\");\n" +
+ " }\n" +
+ " return \"vul/other/onlyForGoogle\";\n" +
"}\n" +
"// 判断是否来自可信代理\n" +
"private boolean isTrustedProxy(String ip) {\n" +
- " return Arrays.asList(\"127.0.0.1\", \"192.168.1.1\", \"10.0.0.1\").contains(ip);\n" +
+ " return Arrays.asList(\"192.168.1.1\", \"10.0.0.1\").contains(ip);\n" +
"}"
const vulCsrf = "public R vul(String receiver, String amount, @AuthenticationPrincipal UserDetails userDetails){\n" +
@@ -1306,7 +1828,7 @@ const safeCsrfToken = "public Map safeCsrf(String receiver,Strin
"\n" +
" String sessionToken = (String) session.getAttribute(\"csrfToken\");\n" +
" Map result = new HashMap<>();\n" +
- " if (!csrfToken.equals(sessionToken)) {\n" +
+ " if (!constantTimeEquals(csrfToken, sessionToken)) {\n" +
" result.put(\"success\", false);\n" +
" result.put(\"message\", \"Token失效!\");\n" +
" return result;\n" +
@@ -1316,25 +1838,53 @@ const safeCsrfToken = "public Map safeCsrf(String receiver,Strin
" result.put(\"amount\", amount);\n" +
" result.put(\"csrfToken\", csrfToken);\n" +
" return result;\n" +
+ "}\n" +
+ "\n" +
+ "private boolean constantTimeEquals(String requestToken, String sessionToken) {\n" +
+ " if (requestToken == null || sessionToken == null) {\n" +
+ " return false;\n" +
+ " }\n" +
+ " return MessageDigest.isEqual(\n" +
+ " requestToken.getBytes(StandardCharsets.UTF_8),\n" +
+ " sessionToken.getBytes(StandardCharsets.UTF_8)\n" +
+ " );\n" +
"}"
const safeCsrfReferer = "public Map safe2(HttpServletRequest request,String receiver,String amount, @AuthenticationPrincipal UserDetails userDetails, HttpSession session) {\n" +
" String currentUser = userDetails.getUsername();\n" +
" Map result = new HashMap<>();\n" +
- " String referer = request.getHeader(\"referer\");\n" +
- " if (referer == null || !referer.startsWith(\"http://127.0.0.1\")) {\n" +
+ " String originOrReferer = request.getHeader(\"Origin\");\n" +
+ " if (originOrReferer == null) {\n" +
+ " originOrReferer = request.getHeader(\"Referer\");\n" +
+ " }\n" +
+ " if (!isTrustedSameOrigin(request, originOrReferer)) {\n" +
" result.put(\"success\", false);\n" +
- " result.put(\"message\", \"referer无效!\");\n" +
+ " result.put(\"message\", \"Origin/Referer无效!\");\n" +
" return result;\n" +
" }\n" +
" result.put(\"currentUser\", currentUser);\n" +
" result.put(\"receiver\", receiver);\n" +
" result.put(\"amount\", amount);\n" +
" return result;\n" +
+ "}\n" +
+ "\n" +
+ "private boolean isTrustedSameOrigin(HttpServletRequest request, String originOrReferer) {\n" +
+ " if (originOrReferer == null) {\n" +
+ " return false;\n" +
+ " }\n" +
+ " try {\n" +
+ " URI uri = new URI(originOrReferer);\n" +
+ " int actualPort = uri.getPort() == -1 ? defaultPort(uri.getScheme()) : uri.getPort();\n" +
+ " return request.getScheme().equalsIgnoreCase(uri.getScheme())\n" +
+ " && request.getServerName().equalsIgnoreCase(uri.getHost())\n" +
+ " && request.getServerPort() == actualPort;\n" +
+ " } catch (URISyntaxException e) {\n" +
+ " return false;\n" +
+ " }\n" +
"}"
// 跨域安全问题
-const vulCORS = "public String vul(HttpServletRequest request, HttpServletResponse response) {\n" +
- " String origin = request.getHeader(\"origin\");\n" +
+const vulCORS = "public R vul(HttpServletRequest request, HttpServletResponse response) {\n" +
+ " String origin = request.getHeader(\"Origin\");\n" +
"\n" +
" if (origin != null) {\n" +
" response.setHeader(\"Access-Control-Allow-Origin\", origin);\n" +
@@ -1345,21 +1895,36 @@ const vulCORS = "public String vul(HttpServletRequest request, HttpServletRespon
" // 允许携带 Cookie 或其他凭证\n" +
" response.setHeader(\"Access-Control-Allow-Credentials\", \"true\");\n" +
" response.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n" +
+ " response.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization, X-Requested-With\");\n" +
+ " response.setHeader(\"Vary\", \"Origin\");\n" +
"\n" +
- " return \"CORS漏洞演示:username:admin,password:Admin123\";\n" +
+ " return R.ok(\"CORS漏洞演示:username:admin,password:Admin123\");\n" +
"}"
-const safeCORS = "@CrossOrigin(origins = {\"http://127.0.0.1:8080\", \"https://127.0.0.1:8080\"}, allowCredentials = \"true\")\n" +
- "public String safe(HttpServletRequest request, HttpServletResponse response) {\n" +
- " // 记录安全 CORS 请求来源\n" +
- " String origin = request.getHeader(\"origin\");\n" +
- " // 允许携带凭证,但前提是 `Access-Control-Allow-Origin` 与可信来源匹配\n" +
+const safeCORS = "private static final Set TRUSTED_ORIGINS = new HashSet<>(Arrays.asList(\n" +
+ " \"http://127.0.0.1:8080\",\n" +
+ " \"https://127.0.0.1:8080\"\n" +
+ "));\n" +
+ "\n" +
+ "public R safe(HttpServletRequest request, HttpServletResponse response) {\n" +
+ " String origin = request.getHeader(\"Origin\");\n" +
+ " response.setHeader(\"Vary\", \"Origin\");\n" +
+ " if (origin == null) {\n" +
+ " return R.ok(\"同源请求不需要CORS响应头\");\n" +
+ " }\n" +
+ " if (!TRUSTED_ORIGINS.contains(origin)) {\n" +
+ " response.setStatus(HttpServletResponse.SC_FORBIDDEN);\n" +
+ " return R.error(HttpServletResponse.SC_FORBIDDEN, \"Origin不在CORS白名单\");\n" +
+ " }\n" +
+ " response.setHeader(\"Access-Control-Allow-Origin\", origin);\n" +
" response.setHeader(\"Access-Control-Allow-Credentials\", \"true\");\n" +
+ " response.setHeader(\"Access-Control-Allow-Methods\", \"GET, OPTIONS\");\n" +
+ " response.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\n" +
"\n" +
- " return \"配置CORS可信源白名单\";\n" +
+ " return R.ok(\"配置CORS可信源白名单\");\n" +
"}\n"
-const vulJSONP = 'public void vul(HttpServletRequest request, HttpServletResponse response) throws IOException, java.io.IOException {\n' +
+const vulJSONP = 'public void vul(HttpServletRequest request, HttpServletResponse response) throws IOException {\n' +
' String callback = request.getParameter("callback");\n' +
' String sensitiveData = "{\\"username\\":\\"admin\\",\\"password\\":\\"Admin123\\"}";\n' +
'\n' +
@@ -1367,15 +1932,27 @@ const vulJSONP = 'public void vul(HttpServletRequest request, HttpServletRespons
' String jsonpResponse = callback + "(" + sensitiveData + ");";\n' +
'\n' +
' // 设置响应类型为 JavaScript 脚本\n' +
- ' response.setContentType("application/javascript");\n' +
+ ' response.setContentType("application/javascript;charset=UTF-8");\n' +
' response.getWriter().write(jsonpResponse);\n' +
'}\n'
-const safeJSONP = "// 校验回调函数名是否合法\n" +
- "if (callback == null || !callback.matches(\"^[a-zA-Z_$][a-zA-Z0-9_$]*$\")) {\n" +
- " response.setStatus(HttpServletResponse.SC_BAD_REQUEST);\n" +
- " response.getWriter().write(\"Invalid callback\");\n" +
- " return;\n" +
+const safeJSONP = "private static final Pattern JSONP_CALLBACK_PATTERN = Pattern.compile(\n" +
+ " \"^[A-Za-z_$][A-Za-z0-9_$]*(\\\\.[A-Za-z_$][A-Za-z0-9_$]*)*$\"\n" +
+ ");\n" +
+ "\n" +
+ "public void safe(HttpServletRequest request, HttpServletResponse response) throws IOException {\n" +
+ " String callback = request.getParameter(\"callback\");\n" +
+ " // 校验回调函数名是否合法\n" +
+ " if (callback == null || !JSONP_CALLBACK_PATTERN.matcher(callback).matches()) {\n" +
+ " response.setStatus(HttpServletResponse.SC_BAD_REQUEST);\n" +
+ " response.getWriter().write(\"Invalid callback\");\n" +
+ " return;\n" +
+ " }\n" +
+ "\n" +
+ " String publicData = \"{\\\"message\\\":\\\"public data only\\\"}\";\n" +
+ " response.setContentType(\"application/javascript;charset=UTF-8\");\n" +
+ " response.setHeader(\"X-Content-Type-Options\", \"nosniff\");\n" +
+ " response.getWriter().write(callback + \"(\" + publicData + \");\");\n" +
"}"
const vulDos = "public void vul(Integer width,Integer height,HttpServletResponse response) throws IOException {\n" +
@@ -1390,6 +1967,19 @@ const vulDos = "public void vul(Integer width,Integer height,HttpServletResponse
" throw new RuntimeException(e);\n" +
" }\n" +
"}"
+const safeDos = "public void safe(Integer width,Integer height,HttpServletResponse response) throws IOException {\n" +
+ " if (width == null || height == null || width <= 0 || height <= 0\n" +
+ " || width > MAX_IMAGE_WIDTH || height > MAX_IMAGE_HEIGHT\n" +
+ " || (long) width * height > MAX_IMAGE_PIXELS) {\n" +
+ " response.setStatus(HttpServletResponse.SC_BAD_REQUEST);\n" +
+ " response.setContentType(\"text/plain;charset=UTF-8\");\n" +
+ " response.getWriter().write(\"图片尺寸超出限制\");\n" +
+ " return;\n" +
+ " }\n" +
+ " response.setContentType(\"image/jpeg\");\n" +
+ " ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(width, height, 4, 3);\n" +
+ " shearCaptcha.write(response.getOutputStream());\n" +
+ "}"
const vul2Dos = "// 如果解压出的文件是ZIP文件,则递归解压\n" +
"if (entry.getName().endsWith(\".zip\")) {\n" +
" // 创建临时文件来存储这个ZIP\n" +
@@ -1434,16 +2024,13 @@ const safeXpath = "public R safe(String username,String password) {\n" +
" String xml = \"admin password \";\n" +
" Document doc = builder.parse(new InputSource(new StringReader(xml)));\n" +
"\n" +
- " // 使用StringEscapeUtils.escapeXml10()方法对用户输入进行XML实体转义\n" +
- " String escapedUsername = StringEscapeUtils.escapeXml10(username);\n" +
- " String escapedPassword = StringEscapeUtils.escapeXml10(password);\n" +
- "\n" +
" XPath xpath = XPathFactory.newInstance().newXPath();\n" +
- " String expression = \"/users/user[username='\" + escapedUsername + \"' and password='\" + escapedPassword + \"']\";\n" +
+ " xpath.setXPathVariableResolver(variableName -> resolveXPathVariable(variableName, username, password));\n" +
+ " String expression = \"/users/user[username=$username and password=$password]\";\n" +
" NodeList nodes = (NodeList) xpath.evaluate(expression, doc, XPathConstants.NODESET);\n" +
"\n" +
" if (nodes.getLength() > 0) {\n" +
- " return R.ok(\"用户名和密码验证通过!欢迎:\" + escapedUsername);\n" +
+ " return R.ok(\"用户名和密码验证通过!欢迎:\" + username);\n" +
" } else {\n" +
" return R.error(\"认证失败:用户名或密码错误\");\n" +
" }\n" +
@@ -1549,7 +2136,7 @@ const springBootSwagger = "return new Docket(DocumentationType.OAS_30)\n" +
const springBootActuator = "management:\n" +
" # 端点信息接口使用的端口,为了和主系统接口使用的端口进行分离\n" +
" server:\n" +
- " port: 8080\n" +
+ " port: 80\n" +
" # 端点健康情况,默认值\"never\",设置为\"always\"可以显示硬盘使用情况和线程情况\n" +
" endpoint:\n" +
" health:\n" +
@@ -1579,19 +2166,18 @@ const springBootActuator = "management:\n" +
"jolokia 通过HTTP暴露JMX beans(当Jolokia在类路径上时,WebFlux不可用) Yes\n" +
"logfile 返回日志文件内容(如果设置了logging.file或logging.path属性的话),支持使用HTTP Range头接收日志文件内容的部分信息 Yes\n" +
"prometheus 以可以被Prometheus服务器抓取的格式显示metrics信息 Yes";
-const springBootDruid = "druid:\n" +
- " ...\n" +
- " filters: stat,log4j # wall 这里关闭sql防火墙\n" +
- " stat-view-servlet:\n" +
- " enabled: true\n" +
- " url-pattern: /druid/*\n" +
- "# login-username: admin\n" +
- "# login-password: admin\n" +
- " reset-enable: false\n" +
- " # 防火墙配置\n" +
- "# wall:\n" +
- "# config:\n" +
- "# multi-statement-allow: false"
+const springBootDruid = "@Configuration\n" +
+ "public class DruidMonitorConfig {\n" +
+ " @Bean\n" +
+ " public ServletRegistrationBean druidStatViewServlet() {\n" +
+ " ServletRegistrationBean registrationBean =\n" +
+ " new ServletRegistrationBean<>(new StatViewServlet(), \"/druid/*\");\n" +
+ " registrationBean.addInitParameter(\"resetEnable\", \"false\");\n" +
+ " return registrationBean;\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "// SecurityConfigurer 中放行 /druid/**,且未设置登录账号密码,会导致Druid监控台暴露。"
const dirTraversal = 'public String listDirectory(String dir) {\n' +
' String staticFolderPath = sysConstant.getStaticFolder();\n' +
@@ -1632,15 +2218,18 @@ const safe1ListDirectory = 'public String safe1(String dir) {\n' +
'}'
const safe2ListDirectory = "public String safe2(String dir) {\n" +
- " String staticFolderPath = sysConstant.getStaticFolder();\n" +
- " File baseDir = new File(staticFolderPath);\n" +
- " File requestedDir = new File(baseDir, dir);\n" +
+ " File baseDir = resolveStaticBaseDir();\n" +
+ " String relativeDir = normalizeRelativeDir(dir);\n" +
"\n" +
" // 检查请求的目录是否在规定目录内\n" +
"try {\n" +
- " if (!requestedDir.getCanonicalPath().startsWith(baseDir.getCanonicalPath()) || !requestedDir.isDirectory()) {\n" +
+ " Path basePath = baseDir.getCanonicalFile().toPath();\n" +
+ " File requestedDir = new File(baseDir, relativeDir);\n" +
+ " Path requestedPath = requestedDir.getCanonicalFile().toPath();\n" +
+ " if (!requestedPath.startsWith(basePath) || !requestedDir.isDirectory()) {\n" +
" return \"Directory not found or access denied.\";\n" +
" }\n" +
+ " return renderDirectoryListing(dir, requestedDir, true);\n" +
"} catch (IOException e) {\n" +
" return \"Error resolving directory path.\";\n" +
"}\n" +
@@ -1766,47 +2355,71 @@ const vul2Reverse = "const publicKey = `-----BEGIN PUBLIC KEY-----\n" +
"{\"encryptedUsername\":\"iDF5BNv1zaM0V9qog0qzlUES3sCGYqmvrKiqPIvUgP5qE0pYn9XN3btW3PbRwLuySeruK2i8lem+L67w5+fFQBuRrpettLrHl8izIRp2W+nq9o9Kg/LSa3/+JynFoUHxrvQ2taNM1nustROpkBjJMbTOK52S6ZBa0quMw+wjfR1XExlzc99U1WJQfRAqj7Gsl9EPydRIh8vs4S/Nen5kf/dL3ZikfMbCUUBonRlYy6a3nWJ412P+hxRbSl80Z8aQKw9lH4+Iju80oFmQ6DuS6Ce70h88z/Va+xzXHDzM8w6h5iqQLzq3Kj/E+b/wsn6eM7v+LEC8LwLQ/t8z8tki9g==\",\n" +
"\"encryptedPassword\":\"nDI0/PBwsFHnRRw7Z4gHZ6G8Uaq7BUjUxnTDw7bkR9nrTkoHfcDLKUddj2JS7WWbOyuwsUFce3/tXJYQWNMFQqGRtf6jXxFAlvTvBkRdsZXOIU+Abb4EqYw670xd5UTeAQ0lI5KNXtw6e/VbnXyX+STJdN2SO7FLbvZ4sM6gLQSVWLo/+pZsYxKlEUNxew2svlzDZtqKnyF12bzakWfzaWuovLnYCCEXV1oAJCErjgfoOS2wJADdgU0wE6KlFDMNjsCvONmO6KZpmJQ1GOq3MpyqySq8eyJkYG3cDSRo5nDo2YOcevOHifzMnKbrU9gh4/RUj8sxrykdqgLmzX3rhw==\"}"
+const vul1Credential = "public R generateJWT(String username, String role) {\n" +
+ " String jwt = Jwts.builder()\n" +
+ " .setSubject(username)\n" +
+ " .claim(\"role\", role)\n" +
+ " .signWith(jwtKey())\n" +
+ " .compact();\n" +
+ " return R.ok(jwt);\n" +
+ "}\n" +
+ "\n" +
+ "public R vul1(String jwt) {\n" +
+ " String user = Jwts.parser()\n" +
+ " .setSigningKey(jwtKey())\n" +
+ " .parseClaimsJws(jwt)\n" +
+ " .getBody()\n" +
+ " .getSubject();\n" +
+ " String role = Jwts.parserBuilder()\n" +
+ " .setSigningKey(jwtKey())\n" +
+ " .build()\n" +
+ " .parseClaimsJws(jwt)\n" +
+ " .getBody()\n" +
+ " .get(\"role\", String.class);\n" +
+ " return R.ok(\"JWT解析成功,user:\" + user + \",role:\" + role);\n" +
+ "}"
+
+const vul2Credential = "vul2Credential"
+
+
// java专题 SPEL注入
const spelVul = "public R vul(String ex) {\n" +
- " // 创建SpEL解析器,ExpressionParser接口用于表示解析器,SpelExpressionParser为默认实现\n" +
- " ExpressionParser parser = new SpelExpressionParser();\n" +
- " \n" +
- " // Expression expression = parser.parseExpression(ex);\n" +
- " // String result = expression.getValue().toString();\n" +
- " \n" +
- " // 构造上下文 上下文其实就是设置好某些变量的值,执行表达式时根据这些设置好的内容区获取值 在不配置的情况下具有默认类型的上下文\n" +
- " EvaluationContext evaluationContext = new StandardEvaluationContext();\n" +
- " \n" +
- " // 解析表达式,将用户输入的字符串解析为Expression对象\n" +
- " Expression exp = parser.parseExpression(ex);\n" +
- " \n" +
- " // 通过上下文计算表达式的值,并将结果转换为字符串\n" +
- " String result = exp.getValue(evaluationContext).toString();\n" +
- " return R.ok(result);\n" +
+ " try {\n" +
+ " ExpressionParser parser = new SpelExpressionParser();\n" +
+ " EvaluationContext evaluationContext = new StandardEvaluationContext();\n" +
+ " Expression exp = parser.parseExpression(ex);\n" +
+ " Object result = exp.getValue(evaluationContext);\n" +
+ " return R.ok(String.valueOf(result));\n" +
+ " } catch (Exception e) {\n" +
+ " return R.error(\"SPEL表达式执行失败:\" + e.getMessage());\n" +
+ " }\n" +
"}"
const spelSafe = "public R safe(String ex) {\n" +
- " ExpressionParser parser = new SpelExpressionParser();\n" +
- " \n" +
- " // 使用 SimpleEvaluationContext 限制表达式功能(Java类型引用、构造函数调用、Bean引用),防止危险的操作\n" +
- " EvaluationContext simpleContext = SimpleEvaluationContext.forReadOnlyDataBinding().build();\n" +
- " \n" +
- " Expression exp = parser.parseExpression(ex);\n" +
- " \n" +
- " String result = exp.getValue(simpleContext).toString();\n" +
- " return R.ok(result);\n" +
+ " try {\n" +
+ " ExpressionParser parser = new SpelExpressionParser();\n" +
+ " // 使用 SimpleEvaluationContext 限制 Java 类型引用、构造函数调用、Bean 引用等危险能力\n" +
+ " EvaluationContext simpleContext = SimpleEvaluationContext.forReadOnlyDataBinding().build();\n" +
+ " Expression exp = parser.parseExpression(ex);\n" +
+ " Object result = exp.getValue(simpleContext);\n" +
+ " return R.ok(String.valueOf(result));\n" +
+ " } catch (Exception e) {\n" +
+ " return R.error(\"表达式被安全上下文限制:\" + e.getMessage());\n" +
+ " }\n" +
"}\n"
const sstiVul = "public String vul1(@RequestParam String para, Model model) {\n" +
- " // 用户输入直接拼接到模板路径,可能导致SSTI(服务器端模板注入)漏洞\n" +
- " return \"/vul/ssti/\" + para;\n" +
+ " // 用户输入直接拼接到模板路径,Thymeleaf 会对视图名中的 __${...}__ 做预处理\n" +
+ " return \"vul/ssti/\" + para;\n" +
"}\n" +
"\n" +
- "public void vul2(@PathVariable String path) {\n" +
+ "public String vul2(@PathVariable String path) {\n" +
+ " // URL 路径变量直接拼接到模板路径,同样会触发 Thymeleaf 视图名预处理\n" +
" log.info(\"SSTI注入:\"+path);\n" +
+ " return \"vul/ssti/\" + path;\n" +
"}\n" +
"\n" +
- "\t// 缺陷组件版本参考\n" +
+ "// 缺陷组件版本参考\n" +
"\n" +
" org.springframework.boot \n" +
" spring-boot-starter-parent \n" +
@@ -1823,57 +2436,54 @@ const sstiVul = "public String vul1(@RequestParam String para, Model model) {\n"
const sstiSafe = "public String safe1(String para, Model model) {\n" +
" List white_list = new ArrayList<>(Arrays.asList(\"vul\", \"ssti\"));\n" +
" if (white_list.contains(para)){\n" +
- " return \"vul/ssti\" + para;\n" +
+ " return \"vul/ssti/\" + para;\n" +
" } else{\n" +
" return \"common/401\";\n" +
" }\n" +
"}\n" +
"@GetMapping(\"/safe2/{path}\")\n" +
- "public void safe2(@PathVariable String path, HttpServletResponse response) {\n" +
+ "public void safe2(@PathVariable String path, HttpServletResponse response) throws IOException {\n" +
" log.info(\"SSTI注入:\"+path);\n" +
+ " response.setContentType(\"text/plain;charset=UTF-8\");\n" +
+ " response.getWriter().write(\"已跳过视图解析,输入路径:\" + path);\n" +
"}"
const vulReadObject = "public R vul(String payload) {\n" +
" try {\n" +
- " payload = payload.replace(\" \", \"+\");\n" +
- " byte[] bytes = Base64.getDecoder().decode(payload);\n" +
- " ByteArrayInputStream stream = new ByteArrayInputStream(bytes);\n" +
- " java.io.ObjectInputStream in = new java.io.ObjectInputStream(stream);\n" +
- " in.readObject();\n" +
- " in.close();\n" +
- " return R.ok(\"[+]Java反序列化:ObjectInputStream.readObject()\");\n" +
+ " byte[] bytes = decodePayload(payload);\n" +
+ " Object obj;\n" +
+ " try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {\n" +
+ " obj = in.readObject();\n" +
+ " }\n" +
+ " return R.ok(\"[+]Java反序列化:\" + obj);\n" +
" } catch (Exception e) {\n" +
" return R.error(\"[-]请输入正确的Payload!\\n\"+e.getMessage());\n" +
" }\n" +
- "}"
+"}"
const safeReadObject1 = "public R safe1(String payload) {\n" +
- " // 安全措施:禁用不安全的反序列化\n" +
+ " // 禁用 Commons Collections 不安全反序列化开关\n" +
" System.setProperty(\"org.apache.commons.collections.enableUnsafeSerialization\", \"false\");\n" +
" try {\n" +
- " payload = payload.replace(\" \", \"+\");\n" +
- " byte[] bytes = Base64.getDecoder().decode(payload);\n" +
- " ByteArrayInputStream stream = new ByteArrayInputStream(bytes);\n" +
- " java.io.ObjectInputStream in = new java.io.ObjectInputStream(stream);\n" +
- " in.readObject();\n" +
- " in.close();\n" +
- " return R.ok(\"[+]Java反序列化:ObjectInputStream.readObject()\");\n" +
+ " byte[] bytes = decodePayload(payload);\n" +
+ " try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {\n" +
+ " in.readObject();\n" +
+ " }\n" +
+ " return R.ok(\"[+]Java反序列化:禁用Commons Collections不安全反序列化开关\");\n" +
" } catch (Exception e) {\n" +
" return R.error(\"[-]请输入正确的Payload!\\n\"+e.getMessage());\n" +
" }\n" +
"}"
const safeReadObject2 = "public R safe2(String payload) {\n" +
" try {\n" +
- " payload = payload.replace(\" \", \"+\");\n" +
- " byte[] bytes = Base64.getDecoder().decode(payload);\n" +
- " ByteArrayInputStream stream = new ByteArrayInputStream(bytes);\n" +
+ " byte[] bytes = decodePayload(payload);\n" +
" // 创建 ValidatingObjectInputStream 对象\n" +
- " ValidatingObjectInputStream ois = new ValidatingObjectInputStream(stream);\n" +
- " // 设置拒绝反序列化的类\n" +
- " ois.reject(java.lang.Runtime.class);\n" +
- " ois.reject(java.lang.ProcessBuilder.class);\n" +
- " // 只允许反序列化Sqli类\n" +
- " ois.accept(Sqli.class);\n" +
- " ois.readObject();\n" +
+ " try (ValidatingObjectInputStream ois = new ValidatingObjectInputStream(new ByteArrayInputStream(bytes))) {\n" +
+ " ois.reject(java.lang.Runtime.class);\n" +
+ " ois.reject(java.lang.ProcessBuilder.class);\n" +
+ " // 只允许反序列化Sqli类\n" +
+ " ois.accept(Sqli.class);\n" +
+ " ois.readObject();\n" +
+ " }\n" +
" return R.ok(\"[+]Java反序列化:ObjectInputStream.readObject()\");\n" +
" } catch (Exception e) {\n" +
" return R.error(\"[-]请输入正确的Payload!\\n\"+e.getMessage());\n" +
@@ -1882,22 +2492,25 @@ const safeReadObject2 = "public R safe2(String payload) {\n" +
const safeReadObject3 = "safeReadObject3"
const vulSnakeYaml = "public R vul(String payload) {\n" +
+ " if (payload == null || payload.trim().isEmpty()) {\n" +
+ " return R.error(\"Payload不能为空\");\n" +
+ " }\n" +
" Yaml y = new Yaml();\n" +
- " y.load(payload);\n" +
- " return R.ok(\"[+]Java反序列化:SnakeYaml\");\n" +
+ " Object result = y.load(payload);\n" +
+ " return R.ok(\"[+]Java反序列化:SnakeYaml原生漏洞,解析结果:\" + result);\n" +
"}\n" +
"\n" +
"// payload示例\n" +
- "payload=!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ['http://127.0.0.1:7777/yaml-payload.jar']]]]\n"
+ "payload=!!top.whgojp.modules.sqli.entity.Sqli {id: 1, username: test, password: pass}\n"
const safeSnakeYaml = "public R safe(String payload) {\n" +
" try {\n" +
" Yaml y = new Yaml(new SafeConstructor());\n" +
- " y.load(payload);\n" +
- " return R.ok(\"[+]Java反序列化:SnakeYaml安全构造\");\n" +
+ " Object result = y.load(payload);\n" +
+ " return R.ok(\"[+]Java反序列化:SnakeYaml安全构造,解析结果:\" + result);\n" +
" } catch (Exception e) {\n" +
- " return R.error(\"[-]Java反序列化:SnakeYaml反序列化失败\");\n" +
+ " return R.error(\"[-]Java反序列化:SnakeYaml反序列化失败:\" + e.getMessage());\n" +
" }\n" +
- "}"
+"}"
const vulXmlDecoder = 'public R vul(String payload) {\n' +
' String[] strCmd = payload.split(" ");\n' +
@@ -2075,3 +2688,24 @@ const vulShiro = "public R getShiroKey(){\n" +
" shiro-spring \n" +
" 1.2.4 \n" +
""
+const JdbcDeserial = "public R jdbc() {\n" +
+ " try (Connection conn = DriverManager.getConnection(url, username, password);\n" +
+ " Statement stmt = conn.createStatement()) {\n" +
+ " ResultSet rs = stmt.executeQuery(\"SELECT malicious_object FROM objects WHERE id = 1\");\n" +
+ " if (rs.next()) {\n" +
+ " byte[] bytes = rs.getBytes(\"malicious_object\");\n" +
+ " try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {\n" +
+ " // 触发反序列化漏洞\n" +
+ " ois.readObject();\n" +
+ " }\n" +
+ " }\n" +
+ " return R.ok(\"触发MYSQL-JDBC反序列化漏洞!\");\n" +
+ " } catch (Exception e) {\n" +
+ " return R.error(\"触发MYSQL-JDBC反序列化漏洞失败:\" + e.getMessage());\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {\n" +
+ " in.defaultReadObject();\n" +
+ " Runtime.getRuntime().exec(command);\n" +
+ "}"
diff --git a/src/main/resources/static/lib/custom-icon/demo.css b/src/main/resources/static/lib/custom-icon/demo.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/custom-icon/demo_index.html b/src/main/resources/static/lib/custom-icon/demo_index.html
old mode 100644
new mode 100755
index e0c9f9f..d51334c
--- a/src/main/resources/static/lib/custom-icon/demo_index.html
+++ b/src/main/resources/static/lib/custom-icon/demo_index.html
@@ -54,6 +54,24 @@
第二步:定义使用 iconfont 的样式
@@ -506,6 +524,33 @@ 第三步:挑选相应图标并获取字体编码,应用于页面
+
+
+
+ 流量
+
+ .icon-liuliang1
+
+
+
+
+
+
+ 流量
+
+ .icon-liuliang
+
+
+
+
+
+
+ horse-solid
+
+ .icon-horse-solid
+
+
+
@@ -1145,6 +1190,30 @@
第二步:挑选相应图标并获取类名,应用于页面:
+
+
+
+
+ 流量
+ #icon-liuliang1
+
+
+
+
+
+
+ 流量
+ #icon-liuliang
+
+
+
+
+
+
+ horse-solid
+ #icon-horse-solid
+
+
diff --git a/src/main/resources/static/lib/custom-icon/iconfont.css b/src/main/resources/static/lib/custom-icon/iconfont.css
old mode 100644
new mode 100755
index 38bcfe1..734b9f4
--- a/src/main/resources/static/lib/custom-icon/iconfont.css
+++ b/src/main/resources/static/lib/custom-icon/iconfont.css
@@ -1,6 +1,6 @@
@font-face {
font-family: "iconfont"; /* Project id 4658507 */
- src: url('iconfont.woff2?t=1732191377206') format('woff2');
+ src: url('iconfont.woff2?t=1740320716474') format('woff2');
}
.iconfont {
@@ -11,6 +11,18 @@
-moz-osx-font-smoothing: grayscale;
}
+.icon-liuliang1:before {
+ content: "\e62f";
+}
+
+.icon-liuliang:before {
+ content: "\e603";
+}
+
+.icon-horse-solid:before {
+ content: "\e6cd";
+}
+
.icon-zhanghao:before {
content: "\e66d";
}
diff --git a/src/main/resources/static/lib/custom-icon/iconfont.js b/src/main/resources/static/lib/custom-icon/iconfont.js
old mode 100644
new mode 100755
index 2168d0b..709460b
--- a/src/main/resources/static/lib/custom-icon/iconfont.js
+++ b/src/main/resources/static/lib/custom-icon/iconfont.js
@@ -1 +1 @@
-window._iconfont_svg_string_4658507=' ',(c=>{var h=(l=(l=document.getElementsByTagName("script"))[l.length-1]).getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var v,a,i,o,t,z=function(h,l){l.parentNode.insertBefore(h,l)};if(h&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(h){console&&console.log(h)}}v=function(){var h,l=document.createElement("div");l.innerHTML=c._iconfont_svg_string_4658507,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(h=document.body).firstChild?z(l,h.firstChild):h.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(v,0):(a=function(){document.removeEventListener("DOMContentLoaded",a,!1),v()},document.addEventListener("DOMContentLoaded",a,!1)):document.attachEvent&&(i=v,o=c.document,t=!1,s(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,m())})}function m(){t||(t=!0,i())}function s(){try{o.documentElement.doScroll("left")}catch(h){return void setTimeout(s,50)}m()}})(window);
\ No newline at end of file
+window._iconfont_svg_string_4658507=' ',(c=>{var h=(l=(l=document.getElementsByTagName("script"))[l.length-1]).getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var v,a,i,o,t,z=function(h,l){l.parentNode.insertBefore(h,l)};if(h&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(h){console&&console.log(h)}}v=function(){var h,l=document.createElement("div");l.innerHTML=c._iconfont_svg_string_4658507,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(h=document.body).firstChild?z(l,h.firstChild):h.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(v,0):(a=function(){document.removeEventListener("DOMContentLoaded",a,!1),v()},document.addEventListener("DOMContentLoaded",a,!1)):document.attachEvent&&(i=v,o=c.document,t=!1,s(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,m())})}function m(){t||(t=!0,i())}function s(){try{o.documentElement.doScroll("left")}catch(h){return void setTimeout(s,50)}m()}})(window);
\ No newline at end of file
diff --git a/src/main/resources/static/lib/custom-icon/iconfont.json b/src/main/resources/static/lib/custom-icon/iconfont.json
old mode 100644
new mode 100755
index f7309b5..a6ac0ff
--- a/src/main/resources/static/lib/custom-icon/iconfont.json
+++ b/src/main/resources/static/lib/custom-icon/iconfont.json
@@ -5,6 +5,27 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
+ {
+ "icon_id": "8371993",
+ "name": "流量",
+ "font_class": "liuliang1",
+ "unicode": "e62f",
+ "unicode_decimal": 58927
+ },
+ {
+ "icon_id": "108775",
+ "name": "流量",
+ "font_class": "liuliang",
+ "unicode": "e603",
+ "unicode_decimal": 58883
+ },
+ {
+ "icon_id": "11992869",
+ "name": "horse-solid",
+ "font_class": "horse-solid",
+ "unicode": "e6cd",
+ "unicode_decimal": 59085
+ },
{
"icon_id": "9454431",
"name": "账号",
diff --git a/src/main/resources/static/lib/custom-icon/iconfont.woff2 b/src/main/resources/static/lib/custom-icon/iconfont.woff2
old mode 100644
new mode 100755
index 109ea9c..495f9ac
Binary files a/src/main/resources/static/lib/custom-icon/iconfont.woff2 and b/src/main/resources/static/lib/custom-icon/iconfont.woff2 differ
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/HELP-US-OUT.txt b/src/main/resources/static/lib/font-awesome-4.7.0/HELP-US-OUT.txt
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/css/font-awesome.css b/src/main/resources/static/lib/font-awesome-4.7.0/css/font-awesome.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/css/font-awesome.min.css b/src/main/resources/static/lib/font-awesome-4.7.0/css/font-awesome.min.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/fonts/FontAwesome.otf b/src/main/resources/static/lib/font-awesome-4.7.0/fonts/FontAwesome.otf
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.eot b/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.eot
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.svg b/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.svg
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf b/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.woff b/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.woff
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 b/src/main/resources/static/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/animated.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/animated.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/bordered-pulled.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/bordered-pulled.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/core.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/core.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/fixed-width.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/fixed-width.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/font-awesome.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/font-awesome.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/icons.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/icons.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/larger.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/larger.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/list.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/list.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/mixins.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/mixins.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/path.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/path.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/rotated-flipped.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/rotated-flipped.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/screen-reader.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/screen-reader.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/stacked.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/stacked.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/less/variables.less b/src/main/resources/static/lib/font-awesome-4.7.0/less/variables.less
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_animated.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_animated.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_bordered-pulled.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_bordered-pulled.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_core.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_core.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_fixed-width.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_fixed-width.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_icons.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_icons.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_larger.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_larger.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_list.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_list.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_mixins.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_mixins.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_path.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_path.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_rotated-flipped.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_rotated-flipped.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_screen-reader.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_screen-reader.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_stacked.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_stacked.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/_variables.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/_variables.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/font-awesome-4.7.0/scss/font-awesome.scss b/src/main/resources/static/lib/font-awesome-4.7.0/scss/font-awesome.scss
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/jq-module/jquery.particleground.min.js b/src/main/resources/static/lib/jq-module/jquery.particleground.min.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/jq-module/paigusu.min.js b/src/main/resources/static/lib/jq-module/paigusu.min.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/jq-module/zyupload/zyupload-1.0.0.min.css b/src/main/resources/static/lib/jq-module/zyupload/zyupload-1.0.0.min.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/jq-module/zyupload/zyupload-1.0.0.min.js b/src/main/resources/static/lib/jq-module/zyupload/zyupload-1.0.0.min.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/jquery-1.6.1.js b/src/main/resources/static/lib/jquery-1.6.1.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/jquery-3.4.1/jquery-3.4.1.min.js b/src/main/resources/static/lib/jquery-3.4.1/jquery-3.4.1.min.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/jquery-3.4.1/jquery.particleground.min.js b/src/main/resources/static/lib/jquery-3.4.1/jquery.particleground.min.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/css/layui.css b/src/main/resources/static/lib/layui-v2.6.3/css/layui.css
old mode 100644
new mode 100755
index 41d779b..bbeba90
--- a/src/main/resources/static/lib/layui-v2.6.3/css/layui.css
+++ b/src/main/resources/static/lib/layui-v2.6.3/css/layui.css
@@ -2261,6 +2261,29 @@ a cite {
background-color: #fff;
border-radius: 2px
}
+.custom-flow-select .layui-form-select .layui-input {
+ font-size: 16px;
+ height: 33.5px !important;
+ line-height: 1.3;
+ line-height: 38px \9;
+ border-width: 1px;
+ border-style: solid;
+ background-color: #fff;
+ border-radius: 2px
+}
+
+/* 仅影响 custom-flow-select 里的 layui 下拉选项 */
+.custom-flow-select .layui-form-select dl dd,
+.custom-flow-select .layui-form-select dl dt {
+ padding: 0 10px !important;
+ line-height: 33.5px !important;
+ font-size: 14px !important; /* 适配文本 */
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+
.layui-input::-webkit-input-placeholder, .layui-select::-webkit-input-placeholder, .layui-textarea::-webkit-input-placeholder {
line-height: 1.3
diff --git a/src/main/resources/static/lib/layui-v2.6.3/css/modules/code.css b/src/main/resources/static/lib/layui-v2.6.3/css/modules/code.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/css/modules/laydate/default/laydate.css b/src/main/resources/static/lib/layui-v2.6.3/css/modules/laydate/default/laydate.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon-ext.png b/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon-ext.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon.png b/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon.png
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/layer.css b/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/layer.css
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-0.gif b/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-0.gif
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-1.gif b/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-1.gif
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-2.gif b/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-2.gif
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.eot b/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.eot
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.svg b/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.svg
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.ttf b/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.ttf
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff b/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff2 b/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff2
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui-v2.6.3/layui.js b/src/main/resources/static/lib/layui-v2.6.3/layui.js
old mode 100644
new mode 100755
diff --git a/src/main/resources/static/lib/layui/css/layui.css b/src/main/resources/static/lib/layui/css/layui.css
new file mode 100644
index 0000000..bbeba90
--- /dev/null
+++ b/src/main/resources/static/lib/layui/css/layui.css
@@ -0,0 +1,5833 @@
+.layui-inline, img {
+ display: inline-block;
+ vertical-align: middle
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight: 400
+}
+
+a, body {
+ color: #333
+}
+
+.layui-edge, .layui-header, .layui-inline, .layui-main {
+ position: relative
+}
+
+.layui-edge, hr {
+ height: 0;
+ overflow: hidden
+}
+
+.layui-layout-body, .layui-side, .layui-side-scroll {
+ overflow-x: hidden
+}
+
+.layui-btn, .layui-edge, .layui-inline, img {
+ vertical-align: middle
+}
+
+.layui-btn, .layui-disabled, .layui-icon, .layui-unselect {
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ -ms-user-select: none
+}
+
+.layui-elip, .layui-form-checkbox span, .layui-form-pane .layui-form-label {
+ text-overflow: ellipsis;
+ white-space: nowrap
+}
+
+.layui-edge, .layui-elip, hr {
+ overflow: hidden
+}
+
+blockquote, body, button, dd, div, dl, dt, form, h1, h2, h3, h4, h5, h6, input, li, ol, p, pre, td, textarea, th, ul {
+ margin: 0;
+ padding: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
+}
+
+a:active, a:hover {
+ outline: 0
+}
+
+img {
+ border: none
+}
+
+li {
+ list-style: none
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0
+}
+
+h4, h5, h6 {
+ font-size: 100%
+}
+
+button, input, optgroup, option, select, textarea {
+ font-family: inherit;
+ font-size: inherit;
+ font-style: inherit;
+ font-weight: inherit;
+ outline: 0
+}
+
+pre {
+ white-space: pre-wrap;
+ white-space: -moz-pre-wrap;
+ white-space: -pre-wrap;
+ white-space: -o-pre-wrap;
+ word-wrap: break-word
+}
+
+body {
+ line-height: 1.6;
+ color: rgba(0, 0, 0, .85);
+ font: 14px Helvetica Neue, Helvetica, PingFang SC, Tahoma, Arial, sans-serif
+}
+
+hr {
+ line-height: 0;
+ margin: 10px 0;
+ padding: 0;
+ border: none !important;
+ border-bottom: 1px solid #eee !important;
+ clear: both;
+ background: 0 0
+}
+
+a {
+ text-decoration: none
+}
+
+a:hover {
+ color: #777
+}
+
+a cite {
+ font-style: normal;
+ *cursor: pointer
+}
+
+.layui-border-box, .layui-border-box * {
+ box-sizing: border-box
+}
+
+.layui-box, .layui-box * {
+ box-sizing: content-box
+}
+
+.layui-clear {
+ clear: both;
+ *zoom: 1
+}
+
+.layui-clear:after {
+ content: '\20';
+ clear: both;
+ *zoom: 1;
+ display: block;
+ height: 0
+}
+
+.layui-inline {
+ *display: inline;
+ *zoom: 1
+}
+
+.layui-edge {
+ display: inline-block;
+ width: 0;
+ border-width: 6px;
+ border-style: dashed;
+ border-color: transparent
+}
+
+.layui-edge-top {
+ top: -4px;
+ border-bottom-color: #999;
+ border-bottom-style: solid
+}
+
+.layui-edge-right {
+ border-left-color: #999;
+ border-left-style: solid
+}
+
+.layui-edge-bottom {
+ top: 2px;
+ border-top-color: #999;
+ border-top-style: solid
+}
+
+.layui-edge-left {
+ border-right-color: #999;
+ border-right-style: solid
+}
+
+.layui-disabled, .layui-disabled:hover {
+ color: #d2d2d2 !important;
+ cursor: not-allowed !important
+}
+
+.layui-circle {
+ border-radius: 100%
+}
+
+.layui-show {
+ display: block !important
+}
+
+.layui-hide {
+ display: none !important
+}
+
+.layui-show-v {
+ visibility: visible !important
+}
+
+.layui-hide-v {
+ visibility: hidden !important
+}
+
+@font-face {
+ font-family: layui-icon;
+ src: url(../font/iconfont.eot?v=256);
+ src: url(../font/iconfont.eot?v=256#iefix) format('embedded-opentype'), url(../font/iconfont.woff2?v=256) format('woff2'), url(../font/iconfont.woff?v=256) format('woff'), url(../font/iconfont.ttf?v=256) format('truetype'), url(../font/iconfont.svg?v=256#layui-icon) format('svg')
+}
+
+.layui-icon {
+ font-family: layui-icon !important;
+ font-size: 16px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale
+}
+
+.layui-icon-reply-fill:before {
+ content: "\e611"
+}
+
+.layui-icon-set-fill:before {
+ content: "\e614"
+}
+
+.layui-icon-menu-fill:before {
+ content: "\e60f"
+}
+
+.layui-icon-search:before {
+ content: "\e615"
+}
+
+.layui-icon-share:before {
+ content: "\e641"
+}
+
+.layui-icon-set-sm:before {
+ content: "\e620"
+}
+
+.layui-icon-engine:before {
+ content: "\e628"
+}
+
+.layui-icon-close:before {
+ content: "\1006"
+}
+
+.layui-icon-close-fill:before {
+ content: "\1007"
+}
+
+.layui-icon-chart-screen:before {
+ content: "\e629"
+}
+
+.layui-icon-star:before {
+ content: "\e600"
+}
+
+.layui-icon-circle-dot:before {
+ content: "\e617"
+}
+
+.layui-icon-chat:before {
+ content: "\e606"
+}
+
+.layui-icon-release:before {
+ content: "\e609"
+}
+
+.layui-icon-list:before {
+ content: "\e60a"
+}
+
+.layui-icon-chart:before {
+ content: "\e62c"
+}
+
+.layui-icon-ok-circle:before {
+ content: "\1005"
+}
+
+.layui-icon-layim-theme:before {
+ content: "\e61b"
+}
+
+.layui-icon-table:before {
+ content: "\e62d"
+}
+
+.layui-icon-right:before {
+ content: "\e602"
+}
+
+.layui-icon-left:before {
+ content: "\e603"
+}
+
+.layui-icon-cart-simple:before {
+ content: "\e698"
+}
+
+.layui-icon-face-cry:before {
+ content: "\e69c"
+}
+
+.layui-icon-face-smile:before {
+ content: "\e6af"
+}
+
+.layui-icon-survey:before {
+ content: "\e6b2"
+}
+
+.layui-icon-tree:before {
+ content: "\e62e"
+}
+
+.layui-icon-ie:before {
+ content: "\e7bb"
+}
+
+.layui-icon-upload-circle:before {
+ content: "\e62f"
+}
+
+.layui-icon-add-circle:before {
+ content: "\e61f"
+}
+
+.layui-icon-download-circle:before {
+ content: "\e601"
+}
+
+.layui-icon-templeate-1:before {
+ content: "\e630"
+}
+
+.layui-icon-util:before {
+ content: "\e631"
+}
+
+.layui-icon-face-surprised:before {
+ content: "\e664"
+}
+
+.layui-icon-edit:before {
+ content: "\e642"
+}
+
+.layui-icon-speaker:before {
+ content: "\e645"
+}
+
+.layui-icon-down:before {
+ content: "\e61a"
+}
+
+.layui-icon-file:before {
+ content: "\e621"
+}
+
+.layui-icon-layouts:before {
+ content: "\e632"
+}
+
+.layui-icon-rate-half:before {
+ content: "\e6c9"
+}
+
+.layui-icon-add-circle-fine:before {
+ content: "\e608"
+}
+
+.layui-icon-prev-circle:before {
+ content: "\e633"
+}
+
+.layui-icon-read:before {
+ content: "\e705"
+}
+
+.layui-icon-404:before {
+ content: "\e61c"
+}
+
+.layui-icon-carousel:before {
+ content: "\e634"
+}
+
+.layui-icon-help:before {
+ content: "\e607"
+}
+
+.layui-icon-code-circle:before {
+ content: "\e635"
+}
+
+.layui-icon-windows:before {
+ content: "\e67f"
+}
+
+.layui-icon-water:before {
+ content: "\e636"
+}
+
+.layui-icon-username:before {
+ content: "\e66f"
+}
+
+.layui-icon-find-fill:before {
+ content: "\e670"
+}
+
+.layui-icon-about:before {
+ content: "\e60b"
+}
+
+.layui-icon-location:before {
+ content: "\e715"
+}
+
+.layui-icon-up:before {
+ content: "\e619"
+}
+
+.layui-icon-pause:before {
+ content: "\e651"
+}
+
+.layui-icon-date:before {
+ content: "\e637"
+}
+
+.layui-icon-layim-uploadfile:before {
+ content: "\e61d"
+}
+
+.layui-icon-delete:before {
+ content: "\e640"
+}
+
+.layui-icon-play:before {
+ content: "\e652"
+}
+
+.layui-icon-top:before {
+ content: "\e604"
+}
+
+.layui-icon-firefox:before {
+ content: "\e686"
+}
+
+.layui-icon-friends:before {
+ content: "\e612"
+}
+
+.layui-icon-refresh-3:before {
+ content: "\e9aa"
+}
+
+.layui-icon-ok:before {
+ content: "\e605"
+}
+
+.layui-icon-layer:before {
+ content: "\e638"
+}
+
+.layui-icon-face-smile-fine:before {
+ content: "\e60c"
+}
+
+.layui-icon-dollar:before {
+ content: "\e659"
+}
+
+.layui-icon-group:before {
+ content: "\e613"
+}
+
+.layui-icon-layim-download:before {
+ content: "\e61e"
+}
+
+.layui-icon-picture-fine:before {
+ content: "\e60d"
+}
+
+.layui-icon-link:before {
+ content: "\e64c"
+}
+
+.layui-icon-diamond:before {
+ content: "\e735"
+}
+
+.layui-icon-log:before {
+ content: "\e60e"
+}
+
+.layui-icon-key:before {
+ content: "\e683"
+}
+
+.layui-icon-rate-solid:before {
+ content: "\e67a"
+}
+
+.layui-icon-fonts-del:before {
+ content: "\e64f"
+}
+
+.layui-icon-unlink:before {
+ content: "\e64d"
+}
+
+.layui-icon-fonts-clear:before {
+ content: "\e639"
+}
+
+.layui-icon-triangle-r:before {
+ content: "\e623"
+}
+
+.layui-icon-circle:before {
+ content: "\e63f"
+}
+
+.layui-icon-radio:before {
+ content: "\e643"
+}
+
+.layui-icon-align-center:before {
+ content: "\e647"
+}
+
+.layui-icon-align-right:before {
+ content: "\e648"
+}
+
+.layui-icon-align-left:before {
+ content: "\e649"
+}
+
+.layui-icon-loading-1:before {
+ content: "\e63e"
+}
+
+.layui-icon-return:before {
+ content: "\e65c"
+}
+
+.layui-icon-fonts-strong:before {
+ content: "\e62b"
+}
+
+.layui-icon-upload:before {
+ content: "\e67c"
+}
+
+.layui-icon-dialogue:before {
+ content: "\e63a"
+}
+
+.layui-icon-video:before {
+ content: "\e6ed"
+}
+
+.layui-icon-headset:before {
+ content: "\e6fc"
+}
+
+.layui-icon-cellphone-fine:before {
+ content: "\e63b"
+}
+
+.layui-icon-add-1:before {
+ content: "\e654"
+}
+
+.layui-icon-face-smile-b:before {
+ content: "\e650"
+}
+
+.layui-icon-fonts-html:before {
+ content: "\e64b"
+}
+
+.layui-icon-screen-full:before {
+ content: "\e622"
+}
+
+.layui-icon-form:before {
+ content: "\e63c"
+}
+
+.layui-icon-cart:before {
+ content: "\e657"
+}
+
+.layui-icon-camera-fill:before {
+ content: "\e65d"
+}
+
+.layui-icon-tabs:before {
+ content: "\e62a"
+}
+
+.layui-icon-heart-fill:before {
+ content: "\e68f"
+}
+
+.layui-icon-fonts-code:before {
+ content: "\e64e"
+}
+
+.layui-icon-ios:before {
+ content: "\e680"
+}
+
+.layui-icon-at:before {
+ content: "\e687"
+}
+
+.layui-icon-fire:before {
+ content: "\e756"
+}
+
+.layui-icon-set:before {
+ content: "\e716"
+}
+
+.layui-icon-fonts-u:before {
+ content: "\e646"
+}
+
+.layui-icon-triangle-d:before {
+ content: "\e625"
+}
+
+.layui-icon-tips:before {
+ content: "\e702"
+}
+
+.layui-icon-picture:before {
+ content: "\e64a"
+}
+
+.layui-icon-more-vertical:before {
+ content: "\e671"
+}
+
+.layui-icon-bluetooth:before {
+ content: "\e689"
+}
+
+.layui-icon-flag:before {
+ content: "\e66c"
+}
+
+.layui-icon-loading:before {
+ content: "\e63d"
+}
+
+.layui-icon-fonts-i:before {
+ content: "\e644"
+}
+
+.layui-icon-refresh-1:before {
+ content: "\e666"
+}
+
+.layui-icon-rmb:before {
+ content: "\e65e"
+}
+
+.layui-icon-addition:before {
+ content: "\e624"
+}
+
+.layui-icon-home:before {
+ content: "\e68e"
+}
+
+.layui-icon-time:before {
+ content: "\e68d"
+}
+
+.layui-icon-user:before {
+ content: "\e770"
+}
+
+.layui-icon-notice:before {
+ content: "\e667"
+}
+
+.layui-icon-chrome:before {
+ content: "\e68a"
+}
+
+.layui-icon-edge:before {
+ content: "\e68b"
+}
+
+.layui-icon-login-weibo:before {
+ content: "\e675"
+}
+
+.layui-icon-voice:before {
+ content: "\e688"
+}
+
+.layui-icon-upload-drag:before {
+ content: "\e681"
+}
+
+.layui-icon-login-qq:before {
+ content: "\e676"
+}
+
+.layui-icon-snowflake:before {
+ content: "\e6b1"
+}
+
+.layui-icon-heart:before {
+ content: "\e68c"
+}
+
+.layui-icon-logout:before {
+ content: "\e682"
+}
+
+.layui-icon-file-b:before {
+ content: "\e655"
+}
+
+.layui-icon-template:before {
+ content: "\e663"
+}
+
+.layui-icon-transfer:before {
+ content: "\e691"
+}
+
+.layui-icon-auz:before {
+ content: "\e672"
+}
+
+.layui-icon-console:before {
+ content: "\e665"
+}
+
+.layui-icon-app:before {
+ content: "\e653"
+}
+
+.layui-icon-prev:before {
+ content: "\e65a"
+}
+
+.layui-icon-website:before {
+ content: "\e7ae"
+}
+
+.layui-icon-next:before {
+ content: "\e65b"
+}
+
+.layui-icon-component:before {
+ content: "\e857"
+}
+
+.layui-icon-android:before {
+ content: "\e684"
+}
+
+.layui-icon-more:before {
+ content: "\e65f"
+}
+
+.layui-icon-login-wechat:before {
+ content: "\e677"
+}
+
+.layui-icon-shrink-right:before {
+ content: "\e668"
+}
+
+.layui-icon-spread-left:before {
+ content: "\e66b"
+}
+
+.layui-icon-camera:before {
+ content: "\e660"
+}
+
+.layui-icon-note:before {
+ content: "\e66e"
+}
+
+.layui-icon-refresh:before {
+ content: "\e669"
+}
+
+.layui-icon-female:before {
+ content: "\e661"
+}
+
+.layui-icon-male:before {
+ content: "\e662"
+}
+
+.layui-icon-screen-restore:before {
+ content: "\e758"
+}
+
+.layui-icon-password:before {
+ content: "\e673"
+}
+
+.layui-icon-senior:before {
+ content: "\e674"
+}
+
+.layui-icon-theme:before {
+ content: "\e66a"
+}
+
+.layui-icon-tread:before {
+ content: "\e6c5"
+}
+
+.layui-icon-praise:before {
+ content: "\e6c6"
+}
+
+.layui-icon-star-fill:before {
+ content: "\e658"
+}
+
+.layui-icon-rate:before {
+ content: "\e67b"
+}
+
+.layui-icon-template-1:before {
+ content: "\e656"
+}
+
+.layui-icon-vercode:before {
+ content: "\e679"
+}
+
+.layui-icon-service:before {
+ content: "\e626"
+}
+
+.layui-icon-cellphone:before {
+ content: "\e678"
+}
+
+.layui-icon-print:before {
+ content: "\e66d"
+}
+
+.layui-icon-cols:before {
+ content: "\e610"
+}
+
+.layui-icon-wifi:before {
+ content: "\e7e0"
+}
+
+.layui-icon-export:before {
+ content: "\e67d"
+}
+
+.layui-icon-rss:before {
+ content: "\e808"
+}
+
+.layui-icon-slider:before {
+ content: "\e714"
+}
+
+.layui-icon-email:before {
+ content: "\e618"
+}
+
+.layui-icon-subtraction:before {
+ content: "\e67e"
+}
+
+.layui-icon-mike:before {
+ content: "\e6dc"
+}
+
+.layui-icon-light:before {
+ content: "\e748"
+}
+
+.layui-icon-gift:before {
+ content: "\e627"
+}
+
+.layui-icon-mute:before {
+ content: "\e685"
+}
+
+.layui-icon-reduce-circle:before {
+ content: "\e616"
+}
+
+.layui-icon-music:before {
+ content: "\e690"
+}
+
+.layui-main {
+ width: 1140px;
+ margin: 0 auto
+}
+
+.layui-header {
+ z-index: 1000;
+ height: 60px
+}
+
+.layui-header a:hover {
+ transition: all .5s;
+ -webkit-transition: all .5s
+}
+
+.layui-side {
+ position: fixed;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 999;
+ width: 200px
+}
+
+.layui-side-scroll {
+ position: relative;
+ width: 220px;
+ height: 100%
+}
+
+.layui-body {
+ position: relative;
+ left: 200px;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 900;
+ width: auto;
+ box-sizing: border-box
+}
+
+.layui-layout-admin .layui-header {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ background-color: #23262E
+}
+
+.layui-layout-admin .layui-side {
+ top: 60px;
+ width: 200px;
+ overflow-x: hidden
+}
+
+.layui-layout-admin .layui-body {
+ position: absolute;
+ top: 60px;
+ padding-bottom: 44px
+}
+
+.layui-layout-admin .layui-main {
+ width: auto;
+ margin: 0 15px
+}
+
+.layui-layout-admin .layui-footer {
+ position: fixed;
+ left: 200px;
+ right: 0;
+ bottom: 0;
+ z-index: 990;
+ height: 44px;
+ line-height: 44px;
+ padding: 0 15px;
+ box-shadow: -1px 0 4px rgb(0 0 0 / 12%);
+ background-color: #FAFAFA
+}
+
+.layui-layout-admin .layui-logo {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 200px;
+ height: 100%;
+ line-height: 60px;
+ text-align: center;
+ color: #009688;
+ font-size: 16px
+}
+
+.layui-layout-admin .layui-header .layui-nav {
+ background: 0 0
+}
+
+.layui-layout-left {
+ position: absolute !important;
+ left: 200px;
+ top: 0
+}
+
+.layui-layout-right {
+ position: absolute !important;
+ right: 0;
+ top: 0
+}
+
+.layui-container {
+ position: relative;
+ margin: 0 auto;
+ padding: 0 15px;
+ box-sizing: border-box
+}
+
+.layui-fluid {
+ position: relative;
+ margin: 0 auto;
+ padding: 0 15px
+}
+
+.layui-row:after, .layui-row:before {
+ content: "";
+ display: block;
+ clear: both
+}
+
+.layui-col-lg1, .layui-col-lg10, .layui-col-lg11, .layui-col-lg12, .layui-col-lg2, .layui-col-lg3, .layui-col-lg4, .layui-col-lg5, .layui-col-lg6, .layui-col-lg7, .layui-col-lg8, .layui-col-lg9, .layui-col-md1, .layui-col-md10, .layui-col-md11, .layui-col-md12, .layui-col-md2, .layui-col-md3, .layui-col-md4, .layui-col-md5, .layui-col-md6, .layui-col-md7, .layui-col-md8, .layui-col-md9, .layui-col-sm1, .layui-col-sm10, .layui-col-sm11, .layui-col-sm12, .layui-col-sm2, .layui-col-sm3, .layui-col-sm4, .layui-col-sm5, .layui-col-sm6, .layui-col-sm7, .layui-col-sm8, .layui-col-sm9, .layui-col-xs1, .layui-col-xs10, .layui-col-xs11, .layui-col-xs12, .layui-col-xs2, .layui-col-xs3, .layui-col-xs4, .layui-col-xs5, .layui-col-xs6, .layui-col-xs7, .layui-col-xs8, .layui-col-xs9 {
+ position: relative;
+ display: block;
+ box-sizing: border-box
+}
+
+.layui-col-xs1, .layui-col-xs10, .layui-col-xs11, .layui-col-xs12, .layui-col-xs2, .layui-col-xs3, .layui-col-xs4, .layui-col-xs5, .layui-col-xs6, .layui-col-xs7, .layui-col-xs8, .layui-col-xs9 {
+ float: left
+}
+
+.layui-col-xs1 {
+ width: 8.33333333%
+}
+
+.layui-col-xs2 {
+ width: 16.66666667%
+}
+
+.layui-col-xs3 {
+ width: 25%
+}
+
+.layui-col-xs4 {
+ width: 33.33333333%
+}
+
+.layui-col-xs5 {
+ width: 41.66666667%
+}
+
+.layui-col-xs6 {
+ width: 50%
+}
+
+.layui-col-xs7 {
+ width: 58.33333333%
+}
+
+.layui-col-xs8 {
+ width: 66.66666667%
+}
+
+.layui-col-xs9 {
+ width: 75%
+}
+
+.layui-col-xs10 {
+ width: 83.33333333%
+}
+
+.layui-col-xs11 {
+ width: 91.66666667%
+}
+
+.layui-col-xs12 {
+ width: 100%
+}
+
+.layui-col-xs-offset1 {
+ margin-left: 8.33333333%
+}
+
+.layui-col-xs-offset2 {
+ margin-left: 16.66666667%
+}
+
+.layui-col-xs-offset3 {
+ margin-left: 25%
+}
+
+.layui-col-xs-offset4 {
+ margin-left: 33.33333333%
+}
+
+.layui-col-xs-offset5 {
+ margin-left: 41.66666667%
+}
+
+.layui-col-xs-offset6 {
+ margin-left: 50%
+}
+
+.layui-col-xs-offset7 {
+ margin-left: 58.33333333%
+}
+
+.layui-col-xs-offset8 {
+ margin-left: 66.66666667%
+}
+
+.layui-col-xs-offset9 {
+ margin-left: 75%
+}
+
+.layui-col-xs-offset10 {
+ margin-left: 83.33333333%
+}
+
+.layui-col-xs-offset11 {
+ margin-left: 91.66666667%
+}
+
+.layui-col-xs-offset12 {
+ margin-left: 100%
+}
+
+@media screen and (max-width: 768px) {
+ .layui-hide-xs {
+ display: none !important
+ }
+
+ .layui-show-xs-block {
+ display: block !important
+ }
+
+ .layui-show-xs-inline {
+ display: inline !important
+ }
+
+ .layui-show-xs-inline-block {
+ display: inline-block !important
+ }
+}
+
+@media screen and (min-width: 768px) {
+ .layui-container {
+ width: 750px
+ }
+
+ .layui-hide-sm {
+ display: none !important
+ }
+
+ .layui-show-sm-block {
+ display: block !important
+ }
+
+ .layui-show-sm-inline {
+ display: inline !important
+ }
+
+ .layui-show-sm-inline-block {
+ display: inline-block !important
+ }
+
+ .layui-col-sm1, .layui-col-sm10, .layui-col-sm11, .layui-col-sm12, .layui-col-sm2, .layui-col-sm3, .layui-col-sm4, .layui-col-sm5, .layui-col-sm6, .layui-col-sm7, .layui-col-sm8, .layui-col-sm9 {
+ float: left
+ }
+
+ .layui-col-sm1 {
+ width: 8.33333333%
+ }
+
+ .layui-col-sm2 {
+ width: 16.66666667%
+ }
+
+ .layui-col-sm3 {
+ width: 25%
+ }
+
+ .layui-col-sm4 {
+ width: 33.33333333%
+ }
+
+ .layui-col-sm5 {
+ width: 41.66666667%
+ }
+
+ .layui-col-sm6 {
+ width: 50%
+ }
+
+ .layui-col-sm7 {
+ width: 58.33333333%
+ }
+
+ .layui-col-sm8 {
+ width: 66.66666667%
+ }
+
+ .layui-col-sm9 {
+ width: 75%
+ }
+
+ .layui-col-sm10 {
+ width: 83.33333333%
+ }
+
+ .layui-col-sm11 {
+ width: 91.66666667%
+ }
+
+ .layui-col-sm12 {
+ width: 100%
+ }
+
+ .layui-col-sm-offset1 {
+ margin-left: 8.33333333%
+ }
+
+ .layui-col-sm-offset2 {
+ margin-left: 16.66666667%
+ }
+
+ .layui-col-sm-offset3 {
+ margin-left: 25%
+ }
+
+ .layui-col-sm-offset4 {
+ margin-left: 33.33333333%
+ }
+
+ .layui-col-sm-offset5 {
+ margin-left: 41.66666667%
+ }
+
+ .layui-col-sm-offset6 {
+ margin-left: 50%
+ }
+
+ .layui-col-sm-offset7 {
+ margin-left: 58.33333333%
+ }
+
+ .layui-col-sm-offset8 {
+ margin-left: 66.66666667%
+ }
+
+ .layui-col-sm-offset9 {
+ margin-left: 75%
+ }
+
+ .layui-col-sm-offset10 {
+ margin-left: 83.33333333%
+ }
+
+ .layui-col-sm-offset11 {
+ margin-left: 91.66666667%
+ }
+
+ .layui-col-sm-offset12 {
+ margin-left: 100%
+ }
+}
+
+@media screen and (min-width: 992px) {
+ .layui-container {
+ width: 970px
+ }
+
+ .layui-hide-md {
+ display: none !important
+ }
+
+ .layui-show-md-block {
+ display: block !important
+ }
+
+ .layui-show-md-inline {
+ display: inline !important
+ }
+
+ .layui-show-md-inline-block {
+ display: inline-block !important
+ }
+
+ .layui-col-md1, .layui-col-md10, .layui-col-md11, .layui-col-md12, .layui-col-md2, .layui-col-md3, .layui-col-md4, .layui-col-md5, .layui-col-md6, .layui-col-md7, .layui-col-md8, .layui-col-md9 {
+ float: left
+ }
+
+ .layui-col-md1 {
+ width: 8.33333333%
+ }
+
+ .layui-col-md2 {
+ width: 16.66666667%
+ }
+
+ .layui-col-md3 {
+ width: 25%
+ }
+
+ .layui-col-md4 {
+ width: 33.33333333%
+ }
+
+ .layui-col-md5 {
+ width: 41.66666667%
+ }
+
+ .layui-col-md6 {
+ width: 50%
+ }
+
+ .layui-col-md7 {
+ width: 58.33333333%
+ }
+
+ .layui-col-md8 {
+ width: 66.66666667%
+ }
+
+ .layui-col-md9 {
+ width: 75%
+ }
+
+ .layui-col-md10 {
+ width: 83.33333333%
+ }
+
+ .layui-col-md11 {
+ width: 91.66666667%
+ }
+
+ .layui-col-md12 {
+ width: 100%
+ }
+
+ .layui-col-md-offset1 {
+ margin-left: 8.33333333%
+ }
+
+ .layui-col-md-offset2 {
+ margin-left: 16.66666667%
+ }
+
+ .layui-col-md-offset3 {
+ margin-left: 25%
+ }
+
+ .layui-col-md-offset4 {
+ margin-left: 33.33333333%
+ }
+
+ .layui-col-md-offset5 {
+ margin-left: 41.66666667%
+ }
+
+ .layui-col-md-offset6 {
+ margin-left: 50%
+ }
+
+ .layui-col-md-offset7 {
+ margin-left: 58.33333333%
+ }
+
+ .layui-col-md-offset8 {
+ margin-left: 66.66666667%
+ }
+
+ .layui-col-md-offset9 {
+ margin-left: 75%
+ }
+
+ .layui-col-md-offset10 {
+ margin-left: 83.33333333%
+ }
+
+ .layui-col-md-offset11 {
+ margin-left: 91.66666667%
+ }
+
+ .layui-col-md-offset12 {
+ margin-left: 100%
+ }
+}
+
+@media screen and (min-width: 1200px) {
+ .layui-container {
+ width: 1170px
+ }
+
+ .layui-hide-lg {
+ display: none !important
+ }
+
+ .layui-show-lg-block {
+ display: block !important
+ }
+
+ .layui-show-lg-inline {
+ display: inline !important
+ }
+
+ .layui-show-lg-inline-block {
+ display: inline-block !important
+ }
+
+ .layui-col-lg1, .layui-col-lg10, .layui-col-lg11, .layui-col-lg12, .layui-col-lg2, .layui-col-lg3, .layui-col-lg4, .layui-col-lg5, .layui-col-lg6, .layui-col-lg7, .layui-col-lg8, .layui-col-lg9 {
+ float: left
+ }
+
+ .layui-col-lg1 {
+ width: 8.33333333%
+ }
+
+ .layui-col-lg2 {
+ width: 16.66666667%
+ }
+
+ .layui-col-lg3 {
+ width: 25%
+ }
+
+ .layui-col-lg4 {
+ width: 33.33333333%
+ }
+
+ .layui-col-lg5 {
+ width: 41.66666667%
+ }
+
+ .layui-col-lg6 {
+ width: 50%
+ }
+
+ .layui-col-lg7 {
+ width: 58.33333333%
+ }
+
+ .layui-col-lg8 {
+ width: 66.66666667%
+ }
+
+ .layui-col-lg9 {
+ width: 75%
+ }
+
+ .layui-col-lg10 {
+ width: 83.33333333%
+ }
+
+ .layui-col-lg11 {
+ width: 91.66666667%
+ }
+
+ .layui-col-lg12 {
+ width: 100%
+ }
+
+ .layui-col-lg-offset1 {
+ margin-left: 8.33333333%
+ }
+
+ .layui-col-lg-offset2 {
+ margin-left: 16.66666667%
+ }
+
+ .layui-col-lg-offset3 {
+ margin-left: 25%
+ }
+
+ .layui-col-lg-offset4 {
+ margin-left: 33.33333333%
+ }
+
+ .layui-col-lg-offset5 {
+ margin-left: 41.66666667%
+ }
+
+ .layui-col-lg-offset6 {
+ margin-left: 50%
+ }
+
+ .layui-col-lg-offset7 {
+ margin-left: 58.33333333%
+ }
+
+ .layui-col-lg-offset8 {
+ margin-left: 66.66666667%
+ }
+
+ .layui-col-lg-offset9 {
+ margin-left: 75%
+ }
+
+ .layui-col-lg-offset10 {
+ margin-left: 83.33333333%
+ }
+
+ .layui-col-lg-offset11 {
+ margin-left: 91.66666667%
+ }
+
+ .layui-col-lg-offset12 {
+ margin-left: 100%
+ }
+}
+
+.layui-col-space1 {
+ margin: -.5px
+}
+
+.layui-col-space1 > * {
+ padding: .5px
+}
+
+.layui-col-space2 {
+ margin: -1px
+}
+
+.layui-col-space2 > * {
+ padding: 1px
+}
+
+.layui-col-space4 {
+ margin: -2px
+}
+
+.layui-col-space4 > * {
+ padding: 2px
+}
+
+.layui-col-space5 {
+ margin: -2.5px
+}
+
+.layui-col-space5 > * {
+ padding: 2.5px
+}
+
+.layui-col-space6 {
+ margin: -3px
+}
+
+.layui-col-space6 > * {
+ padding: 3px
+}
+
+.layui-col-space8 {
+ margin: -4px
+}
+
+.layui-col-space8 > * {
+ padding: 4px
+}
+
+.layui-col-space10 {
+ margin: -5px
+}
+
+.layui-col-space10 > * {
+ padding: 5px
+}
+
+.layui-col-space12 {
+ margin: -6px
+}
+
+.layui-col-space12 > * {
+ padding: 6px
+}
+
+.layui-col-space14 {
+ margin: -7px
+}
+
+.layui-col-space14 > * {
+ padding: 7px
+}
+
+.layui-col-space15 {
+ margin: -7.5px
+}
+
+.layui-col-space15 > * {
+ padding: 7.5px
+}
+
+.layui-col-space16 {
+ margin: -8px
+}
+
+.layui-col-space16 > * {
+ padding: 8px
+}
+
+.layui-col-space18 {
+ margin: -9px
+}
+
+.layui-col-space18 > * {
+ padding: 9px
+}
+
+.layui-col-space20 {
+ margin: -10px
+}
+
+.layui-col-space20 > * {
+ padding: 10px
+}
+
+.layui-col-space22 {
+ margin: -11px
+}
+
+.layui-col-space22 > * {
+ padding: 11px
+}
+
+.layui-col-space24 {
+ margin: -12px
+}
+
+.layui-col-space24 > * {
+ padding: 12px
+}
+
+.layui-col-space25 {
+ margin: -12.5px
+}
+
+.layui-col-space25 > * {
+ padding: 12.5px
+}
+
+.layui-col-space26 {
+ margin: -13px
+}
+
+.layui-col-space26 > * {
+ padding: 13px
+}
+
+.layui-col-space28 {
+ margin: -14px
+}
+
+.layui-col-space28 > * {
+ padding: 14px
+}
+
+.layui-col-space30 {
+ margin: -15px
+}
+
+.layui-col-space30 > * {
+ padding: 15px
+}
+
+.layui-btn, .layui-input, .layui-select, .layui-textarea, .layui-upload-button {
+ outline: 0;
+ -webkit-appearance: none;
+ transition: all .3s;
+ -webkit-transition: all .3s;
+ box-sizing: border-box
+}
+
+.layui-elem-quote {
+ /*margin-bottom: 10px;*/
+ padding: 15px;
+ line-height: 1.6;
+ /*border-left: 5px solid #5FB878;*/
+ /*border-radius: 0 2px 2px 0;*/
+ border-radius: .25rem !important;
+ background-color: #FAFAFA
+}
+.layui-elem-quote-vul {
+ margin-bottom: 10px;
+ padding: 15px;
+ line-height: 1.6;
+ border-left: 5px solid #ec0808;
+ border-radius: 0 2px 2px 0;
+ background-color: #FAFAFA
+}
+
+.layui-quote-nm {
+ border-style: solid;
+ border-width: 1px 1px 1px 1px;
+ background: 0 0
+}
+
+.layui-elem-field {
+ /*margin-bottom: 10px;*/
+ padding: 0;
+ border-width: 1px;
+ border-style: solid
+}
+
+.layui-elem-field legend {
+ margin-left: 20px;
+ padding: 0 10px;
+ font-size: 20px;
+ font-weight: 300
+}
+
+.layui-field-title {
+ border-width: 1px 0 0
+}
+
+.layui-field-box {
+ padding: 15px
+}
+
+.layui-field-title .layui-field-box {
+ padding: 10px 0
+}
+
+.layui-progress {
+ position: relative;
+ height: 6px;
+ border-radius: 20px;
+ background-color: #eee
+}
+
+.layui-progress-bar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 0;
+ max-width: 100%;
+ height: 6px;
+ border-radius: 20px;
+ text-align: right;
+ background-color: #5FB878;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-progress-big, .layui-progress-big .layui-progress-bar {
+ height: 18px;
+ line-height: 18px
+}
+
+.layui-progress-text {
+ position: relative;
+ top: -20px;
+ line-height: 18px;
+ font-size: 12px;
+ color: #666
+}
+
+.layui-progress-big .layui-progress-text {
+ position: static;
+ padding: 0 10px;
+ color: #fff
+}
+
+.layui-collapse {
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px
+}
+
+.layui-colla-content, .layui-colla-item {
+ border-top-width: 1px;
+ border-top-style: solid
+}
+
+.layui-colla-item:first-child {
+ border-top: none
+}
+
+.layui-colla-title {
+ position: relative;
+ height: 42px;
+ line-height: 42px;
+ padding: 0 15px 0 35px;
+ color: #333;
+ background-color: #FAFAFA;
+ cursor: pointer;
+ font-size: 14px;
+ overflow: hidden
+}
+
+.layui-colla-content {
+ display: none;
+ padding: 10px 15px;
+ line-height: 1.6;
+ color: #666
+}
+
+.layui-colla-icon {
+ position: absolute;
+ left: 15px;
+ top: 0;
+ font-size: 14px
+}
+
+.layui-card {
+ margin-bottom: 15px;
+ border-radius: 2px;
+ background-color: #fff;
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .05)
+}
+
+.layui-card:last-child {
+ margin-bottom: 0
+}
+
+.layui-card-header {
+ position: relative;
+ height: 42px;
+ line-height: 42px;
+ padding: 0 15px;
+ border-bottom: 1px solid #f6f6f6;
+ color: #333;
+ border-radius: 2px 2px 0 0;
+ font-size: 14px
+}
+
+.layui-card-body {
+ position: relative;
+ padding: 10px 15px;
+ line-height: 24px
+}
+
+.layui-card-body[pad15] {
+ padding: 15px
+}
+
+.layui-card-body[pad20] {
+ padding: 20px
+}
+
+.layui-card-body .layui-table {
+ margin: 5px 0
+}
+
+.layui-card .layui-tab {
+ margin: 0
+}
+
+.layui-panel {
+ position: relative;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px;
+ box-shadow: 1px 1px 4px rgb(0 0 0 / 8%);
+ background-color: #fff;
+ color: #666
+}
+
+.layui-bg-black, .layui-bg-blue, .layui-bg-cyan, .layui-bg-green, .layui-bg-orange, .layui-bg-red {
+ color: #fff !important
+}
+
+.layui-panel-window {
+ position: relative;
+ padding: 15px;
+ border-radius: 0;
+ border-top: 5px solid #eee;
+ background-color: #fff
+}
+
+.layui-border, .layui-border-black, .layui-border-blue, .layui-border-cyan, .layui-border-green, .layui-border-orange, .layui-border-red {
+ border-width: 1px;
+ border-style: solid
+}
+
+.layui-auxiliar-moving {
+ position: fixed;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ width: 100%;
+ height: 100%;
+ background: 0 0;
+ z-index: 9999999999
+}
+
+.layui-form-label, .layui-form-mid, .layui-form-select, .layui-input-block, .layui-input-inline, .layui-textarea {
+ position: relative;
+}
+
+.layui-bg-red {
+ background-color: #FF5722 !important
+}
+
+.layui-bg-orange {
+ background-color: #FFB800 !important
+}
+
+.layui-bg-green {
+ background-color: #009688 !important
+}
+
+.layui-bg-cyan {
+ background-color: #2F4056 !important
+}
+
+.layui-bg-blue {
+ background-color: #1E9FFF !important
+}
+
+.layui-bg-black {
+ background-color: #393D49 !important
+}
+
+.layui-bg-gray {
+ background-color: #FAFAFA !important;
+ color: #666 !important
+}
+
+.layui-badge-rim, .layui-border, .layui-colla-content, .layui-colla-item, .layui-collapse, .layui-elem-field, .layui-form-pane .layui-form-item[pane], .layui-form-pane .layui-form-label, .layui-input, .layui-layedit, .layui-layedit-tool, .layui-panel, .layui-quote-nm, .layui-select, .layui-tab-bar, .layui-tab-card, .layui-tab-title, .layui-tab-title .layui-this:after, .layui-textarea {
+ border-color: #eee
+}
+
+.layui-border {
+ color: #666 !important
+}
+
+.layui-border-red {
+ border-color: #FF5722 !important;
+ color: #FF5722 !important
+}
+
+.layui-border-orange {
+ border-color: #FFB800 !important;
+ color: #FFB800 !important
+}
+
+.layui-border-green {
+ border-color: #009688 !important;
+ color: #009688 !important
+}
+
+.layui-border-cyan {
+ border-color: #2F4056 !important;
+ color: #2F4056 !important
+}
+
+.layui-border-blue {
+ border-color: #1E9FFF !important;
+ color: #1E9FFF !important
+}
+
+.layui-border-black {
+ border-color: #393D49 !important;
+ color: #393D49 !important
+}
+
+.layui-timeline-item:before {
+ background-color: #eee
+}
+
+.layui-text {
+ line-height: 1.6;
+ font-size: 14px;
+ color: #666
+}
+
+.layui-text h1, .layui-text h2, .layui-text h3 {
+ font-weight: 500;
+ color: #333
+}
+
+.layui-text h1 {
+ font-size: 30px
+}
+
+.layui-text h2 {
+ font-size: 24px
+}
+
+.layui-text h3 {
+ font-size: 18px
+}
+
+.layui-text a:not(.layui-btn) {
+ color: #01AAED
+}
+
+.layui-text a:not(.layui-btn):hover {
+ text-decoration: underline
+}
+
+.layui-text ul {
+ padding: 5px 0 5px 15px
+}
+
+.layui-text ul li {
+ margin-top: 5px;
+ list-style-type: disc
+}
+
+.layui-text em, .layui-word-aux {
+ color: #999 !important;
+ padding-left: 5px !important;
+ padding-right: 5px !important
+}
+
+.layui-font-12 {
+ font-size: 12px
+}
+
+.layui-font-14 {
+ font-size: 14px
+}
+
+.layui-font-16 {
+ font-size: 16px
+}
+
+.layui-font-18 {
+ font-size: 18px
+}
+
+.layui-font-20 {
+ font-size: 20px
+}
+
+.layui-font-red {
+ color: #FF5722 !important
+}
+
+.layui-font-orange {
+ color: #FFB800 !important
+}
+
+.layui-font-green {
+ color: #009688 !important
+}
+
+.layui-font-cyan {
+ color: #2F4056 !important
+}
+
+.layui-font-blue {
+ color: #01AAED !important
+}
+
+.layui-font-black {
+ color: #000 !important
+}
+
+.layui-font-gray {
+ color: #c2c2c2 !important
+}
+
+/*.layui-btn {*/
+/* display: inline-block;*/
+/* height: 38px;*/
+/* line-height: 38px;*/
+/* padding: 0 18px;*/
+/* border: 1px solid transparent;*/
+/* background-color: #009688;*/
+/* color: #fff;*/
+/* white-space: nowrap;*/
+/* text-align: center;*/
+/* font-size: 14px;*/
+/* border-radius: 2px;*/
+/* cursor: pointer*/
+/*}*/
+
+.layui-btn {
+ display: inline-block;
+ height: 38px;
+ line-height: 38px;
+ padding: 0 18px;
+ border: 1px solid transparent;
+ background-color: #009688;
+ color: #fff;
+ white-space: nowrap;
+ text-align: center;
+ font-size: 14px;
+ border-radius: 2px;
+ cursor: pointer
+}
+
+.layui-btn:hover {
+ opacity: .8;
+ filter: alpha(opacity=80);
+ color: #fff
+}
+
+.layui-btn:active {
+ opacity: 1;
+ filter: alpha(opacity=100)
+}
+
+.layui-btn + .layui-btn {
+ margin-left: 10px
+}
+
+.layui-btn-container {
+ font-size: 0
+}
+
+.layui-btn-container .layui-btn {
+ margin-right: 10px;
+ margin-bottom: 10px
+}
+
+.layui-btn-container .layui-btn + .layui-btn {
+ margin-left: 0
+}
+
+.layui-table .layui-btn-container .layui-btn {
+ margin-bottom: 9px
+}
+
+.layui-btn-radius {
+ border-radius: 100px
+}
+
+.layui-btn .layui-icon {
+ padding: 0 2px;
+ vertical-align: middle \9;
+ vertical-align: bottom
+}
+
+.layui-btn-primary {
+ border-color: #d2d2d2;
+ background: 0 0;
+ color: #666
+}
+
+.layui-btn-primary:hover {
+ border-color: #009688;
+ color: #333
+}
+
+.layui-btn-normal {
+ background-color: #1E9FFF
+}
+
+.layui-btn-warm {
+ background-color: #FFB800
+}
+
+.layui-btn-danger {
+ background-color: #FF5722
+}
+
+.layui-btn-checked {
+ background-color: #5FB878
+}
+
+.layui-btn-disabled, .layui-btn-disabled:active, .layui-btn-disabled:hover {
+ border-color: #eee;
+ background-color: #FBFBFB;
+ color: #d2d2d2;
+ cursor: not-allowed;
+ opacity: 1
+}
+
+.layui-btn-lg {
+ height: 44px;
+ line-height: 44px;
+ padding: 0 25px;
+ font-size: 16px
+}
+
+.layui-btn-sm {
+ height: 30px;
+ line-height: 30px;
+ padding: 0 10px;
+ font-size: 12px
+}
+
+.layui-btn-xs {
+ height: 22px;
+ line-height: 22px;
+ padding: 0 5px;
+ font-size: 12px
+}
+
+.layui-btn-xs i {
+ font-size: 12px !important
+}
+
+.layui-btn-group {
+ display: inline-block;
+ vertical-align: middle;
+ font-size: 0
+}
+
+.layui-btn-group .layui-btn {
+ margin-left: 0 !important;
+ margin-right: 0 !important;
+ border-left: 1px solid rgba(255, 255, 255, .5);
+ border-radius: 0
+}
+
+.layui-btn-group .layui-btn-primary {
+ border-left: none
+}
+
+.layui-btn-group .layui-btn-primary:hover {
+ border-color: #d2d2d2;
+ color: #009688
+}
+
+.layui-btn-group .layui-btn:first-child {
+ border-left: none;
+ border-radius: 2px 0 0 2px
+}
+
+.layui-btn-group .layui-btn-primary:first-child {
+ border-left: 1px solid #d2d2d2
+}
+
+.layui-btn-group .layui-btn:last-child {
+ border-radius: 0 2px 2px 0
+}
+
+.layui-btn-group .layui-btn + .layui-btn {
+ margin-left: 0
+}
+
+.layui-btn-group + .layui-btn-group {
+ margin-left: 10px
+}
+
+.layui-btn-fluid {
+ width: 100%
+}
+
+.layui-input, .layui-select, .layui-textarea {
+ height: 38px;
+ line-height: 1.3;
+ line-height: 38px \9;
+ border-width: 1px;
+ border-style: solid;
+ background-color: #fff;
+ border-radius: 2px
+}
+.custom-flow-select .layui-form-select .layui-input {
+ font-size: 16px;
+ height: 33.5px !important;
+ line-height: 1.3;
+ line-height: 38px \9;
+ border-width: 1px;
+ border-style: solid;
+ background-color: #fff;
+ border-radius: 2px
+}
+
+/* 仅影响 custom-flow-select 里的 layui 下拉选项 */
+.custom-flow-select .layui-form-select dl dd,
+.custom-flow-select .layui-form-select dl dt {
+ padding: 0 10px !important;
+ line-height: 33.5px !important;
+ font-size: 14px !important; /* 适配文本 */
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+
+
+.layui-input::-webkit-input-placeholder, .layui-select::-webkit-input-placeholder, .layui-textarea::-webkit-input-placeholder {
+ line-height: 1.3
+}
+
+.layui-input, .layui-textarea {
+ display: block;
+ width: 100%;
+ padding-left: 10px
+}
+
+.layui-input:hover, .layui-textarea:hover {
+ border-color: #eee !important
+}
+
+.layui-input:focus, .layui-textarea:focus {
+ border-color: #d2d2d2 !important
+}
+
+.layui-textarea {
+ min-height: 100px;
+ height: auto;
+ line-height: 20px;
+ padding: 6px 10px;
+ resize: vertical
+}
+
+.layui-select {
+ padding: 0 10px
+}
+
+.layui-form input[type=checkbox], .layui-form input[type=radio], .layui-form select {
+ display: none
+}
+
+.layui-form [lay-ignore] {
+ display: initial
+}
+
+.layui-form-item {
+ margin-bottom: 15px;
+ clear: both;
+ *zoom: 1
+}
+
+.layui-form-item:after {
+ content: '\20';
+ clear: both;
+ *zoom: 1;
+ display: block;
+ height: 0
+}
+
+.layui-form-label {
+ float: left;
+ display: block;
+ padding: 9px 15px;
+ width: 80px;
+ font-weight: 400;
+ line-height: 20px;
+ text-align: right
+}
+
+.layui-form-label-col {
+ display: block;
+ float: none;
+ padding: 9px 0;
+ line-height: 20px;
+ text-align: left
+}
+
+.layui-form-item .layui-inline {
+ margin-bottom: 5px;
+ margin-right: 10px
+}
+
+.layui-input-block {
+ margin-left: 110px;
+ min-height: 36px
+}
+
+.layui-input-inline {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-form-item .layui-input-inline {
+ float: left;
+ width: 190px;
+ margin-right: 10px
+}
+
+.layui-form-text .layui-input-inline {
+ width: auto
+}
+
+.layui-form-mid {
+ float: left;
+ display: block;
+ padding: 9px 0 !important;
+ line-height: 20px;
+ margin-right: 10px
+}
+
+.layui-form-danger + .layui-form-select .layui-input, .layui-form-danger:focus {
+ border-color: #FF5722 !important
+}
+
+.layui-form-select .layui-input {
+ padding-right: 30px;
+ cursor: pointer
+}
+
+.layui-form-select .layui-edge {
+ position: absolute;
+ right: 10px;
+ top: 50%;
+ margin-top: -3px;
+ cursor: pointer;
+ border-width: 6px;
+ border-top-color: #c2c2c2;
+ border-top-style: solid;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-form-select dl {
+ display: none;
+ position: absolute;
+ left: 0;
+ top: 42px;
+ padding: 5px 0;
+ z-index: 899;
+ min-width: 100%;
+ border: 1px solid #d2d2d2;
+ max-height: 300px;
+ overflow-y: auto;
+ background-color: #fff;
+ border-radius: 2px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12);
+ box-sizing: border-box
+}
+
+.layui-form-select dl dd, .layui-form-select dl dt {
+ padding: 0 10px;
+ line-height: 36px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis
+}
+
+.layui-form-select dl dt {
+ font-size: 12px;
+ color: #999
+}
+
+.layui-form-select dl dd {
+ cursor: pointer
+}
+
+.layui-form-select dl dd:hover {
+ background-color: #F6F6F6;
+ -webkit-transition: .5s all;
+ transition: .5s all
+}
+
+.layui-form-select .layui-select-group dd {
+ padding-left: 20px
+}
+
+.layui-form-select dl dd.layui-select-tips {
+ padding-left: 10px !important;
+ color: #999
+}
+
+.layui-form-select dl dd.layui-this {
+ background-color: #5FB878;
+ color: #fff
+}
+
+.layui-form-checkbox, .layui-form-select dl dd.layui-disabled {
+ background-color: #fff
+}
+
+.layui-form-selected dl {
+ display: block
+}
+
+.layui-form-checkbox, .layui-form-checkbox *, .layui-form-switch {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-form-selected .layui-edge {
+ margin-top: -9px;
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+ margin-top: -3px \9
+}
+
+:root .layui-form-selected .layui-edge {
+ margin-top: -9px \0/ IE9
+}
+
+.layui-form-selectup dl {
+ top: auto;
+ bottom: 42px
+}
+
+.layui-select-none {
+ margin: 5px 0;
+ text-align: center;
+ color: #999
+}
+
+.layui-select-disabled .layui-disabled {
+ border-color: #eee !important
+}
+
+.layui-select-disabled .layui-edge {
+ border-top-color: #d2d2d2
+}
+
+.layui-form-checkbox {
+ position: relative;
+ height: 30px;
+ line-height: 30px;
+ margin-right: 10px;
+ padding-right: 30px;
+ cursor: pointer;
+ font-size: 0;
+ -webkit-transition: .1s linear;
+ transition: .1s linear;
+ box-sizing: border-box
+}
+
+.layui-form-checkbox span {
+ padding: 0 10px;
+ height: 100%;
+ font-size: 14px;
+ border-radius: 2px 0 0 2px;
+ background-color: #d2d2d2;
+ color: #fff;
+ overflow: hidden
+}
+
+.layui-form-checkbox:hover span {
+ background-color: #c2c2c2
+}
+
+.layui-form-checkbox i {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 30px;
+ height: 28px;
+ border: 1px solid #d2d2d2;
+ border-left: none;
+ border-radius: 0 2px 2px 0;
+ color: #fff;
+ font-size: 20px;
+ text-align: center
+}
+
+.layui-form-checkbox:hover i {
+ border-color: #c2c2c2;
+ color: #c2c2c2
+}
+
+.layui-form-checked, .layui-form-checked:hover {
+ border-color: #5FB878
+}
+
+.layui-form-checked span, .layui-form-checked:hover span {
+ background-color: #5FB878
+}
+
+.layui-form-checked i, .layui-form-checked:hover i {
+ color: #5FB878
+}
+
+.layui-form-item .layui-form-checkbox {
+ margin-top: 4px
+}
+
+.layui-form-checkbox[lay-skin=primary] {
+ height: auto !important;
+ line-height: normal !important;
+ min-width: 18px;
+ min-height: 18px;
+ border: none !important;
+ margin-right: 0;
+ padding-left: 28px;
+ padding-right: 0;
+ background: 0 0
+}
+
+.layui-form-checkbox[lay-skin=primary] span {
+ padding-left: 0;
+ padding-right: 15px;
+ line-height: 18px;
+ background: 0 0;
+ color: #666
+}
+
+.layui-form-checkbox[lay-skin=primary] i {
+ right: auto;
+ left: 0;
+ width: 16px;
+ height: 16px;
+ line-height: 16px;
+ border: 1px solid #d2d2d2;
+ font-size: 12px;
+ border-radius: 2px;
+ background-color: #fff;
+ -webkit-transition: .1s linear;
+ transition: .1s linear
+}
+
+.layui-form-checkbox[lay-skin=primary]:hover i {
+ border-color: #5FB878;
+ color: #fff
+}
+
+.layui-form-checked[lay-skin=primary] i {
+ border-color: #5FB878 !important;
+ background-color: #5FB878;
+ color: #fff
+}
+
+.layui-checkbox-disbaled[lay-skin=primary] span {
+ background: 0 0 !important;
+ color: #c2c2c2 !important
+}
+
+.layui-checkbox-disbaled[lay-skin=primary]:hover i {
+ border-color: #d2d2d2
+}
+
+.layui-form-item .layui-form-checkbox[lay-skin=primary] {
+ margin-top: 10px
+}
+
+.layui-form-switch {
+ position: relative;
+ height: 22px;
+ line-height: 22px;
+ min-width: 35px;
+ padding: 0 5px;
+ margin-top: 8px;
+ border: 1px solid #d2d2d2;
+ border-radius: 20px;
+ cursor: pointer;
+ background-color: #fff;
+ -webkit-transition: .1s linear;
+ transition: .1s linear
+}
+
+.layui-form-switch i {
+ position: absolute;
+ left: 5px;
+ top: 3px;
+ width: 16px;
+ height: 16px;
+ border-radius: 20px;
+ background-color: #d2d2d2;
+ -webkit-transition: .1s linear;
+ transition: .1s linear
+}
+
+.layui-form-switch em {
+ position: relative;
+ top: 0;
+ width: 25px;
+ margin-left: 21px;
+ padding: 0 !important;
+ text-align: center !important;
+ color: #999 !important;
+ font-style: normal !important;
+ font-size: 12px
+}
+
+.layui-form-onswitch {
+ border-color: #5FB878;
+ background-color: #5FB878
+}
+
+.layui-checkbox-disbaled, .layui-checkbox-disbaled i {
+ border-color: #eee !important
+}
+
+.layui-form-onswitch i {
+ left: 100%;
+ margin-left: -21px;
+ background-color: #fff
+}
+
+.layui-form-onswitch em {
+ margin-left: 5px;
+ margin-right: 21px;
+ color: #fff !important
+}
+
+.layui-checkbox-disbaled span {
+ background-color: #eee !important
+}
+
+.layui-checkbox-disbaled em {
+ color: #d2d2d2 !important
+}
+
+.layui-checkbox-disbaled:hover i {
+ color: #fff !important
+}
+
+[lay-radio] {
+ display: none
+}
+
+.layui-form-radio, .layui-form-radio * {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-form-radio {
+ line-height: 28px;
+ margin: 6px 10px 0 0;
+ padding-right: 10px;
+ cursor: pointer;
+ font-size: 0
+}
+
+.layui-form-radio * {
+ font-size: 14px
+}
+
+.layui-form-radio > i {
+ margin-right: 8px;
+ font-size: 22px;
+ color: #c2c2c2
+}
+
+.layui-form-radio:hover *, .layui-form-radioed, .layui-form-radioed > i {
+ color: #5FB878
+}
+
+.layui-radio-disbaled > i {
+ color: #eee !important
+}
+
+.layui-radio-disbaled * {
+ color: #c2c2c2 !important
+}
+
+.layui-form-pane .layui-form-label {
+ width: 110px;
+ padding: 8px 15px;
+ height: 38px;
+ line-height: 20px;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px 0 0 2px;
+ text-align: center;
+ background-color: #FBFBFB;
+ overflow: hidden;
+ box-sizing: border-box
+}
+
+.layui-form-pane .layui-input-inline {
+ margin-left: -1px
+}
+
+.layui-form-pane .layui-input-block {
+ margin-left: 110px;
+ left: -1px
+}
+
+.layui-form-pane .layui-input {
+ border-radius: 0 2px 2px 0
+}
+
+.layui-form-pane .layui-form-text .layui-form-label {
+ float: none;
+ width: 100%;
+ border-radius: 2px;
+ box-sizing: border-box;
+ text-align: left
+}
+
+.layui-form-pane .layui-form-text .layui-input-inline {
+ display: block;
+ margin: 0;
+ top: -1px;
+ clear: both
+}
+
+.layui-form-pane .layui-form-text .layui-input-block {
+ margin: 0;
+ left: 0;
+ top: -1px
+}
+
+.layui-form-pane .layui-form-text .layui-textarea {
+ min-height: 100px;
+ border-radius: 0 0 2px 2px
+}
+
+.layui-form-pane .layui-form-checkbox {
+ margin: 4px 0 4px 10px
+}
+
+.layui-form-pane .layui-form-radio, .layui-form-pane .layui-form-switch {
+ margin-top: 6px;
+ margin-left: 10px
+}
+
+.layui-form-pane .layui-form-item[pane] {
+ position: relative;
+ border-width: 1px;
+ border-style: solid
+}
+
+.layui-form-pane .layui-form-item[pane] .layui-form-label {
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 100%;
+ border-width: 0 1px 0 0
+}
+
+.layui-form-pane .layui-form-item[pane] .layui-input-inline {
+ margin-left: 110px
+}
+
+@media screen and (max-width: 450px) {
+ .layui-form-item .layui-form-label {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap
+ }
+
+ .layui-form-item .layui-inline {
+ display: block;
+ margin-right: 0;
+ margin-bottom: 20px;
+ clear: both
+ }
+
+ .layui-form-item .layui-inline:after {
+ content: '\20';
+ clear: both;
+ display: block;
+ height: 0
+ }
+
+ .layui-form-item .layui-input-inline {
+ display: block;
+ float: none;
+ left: -3px;
+ width: auto;
+ margin: 0 0 10px 112px
+ }
+
+ .layui-form-item .layui-input-inline + .layui-form-mid {
+ margin-left: 110px;
+ top: -5px;
+ padding: 0
+ }
+
+ .layui-form-item .layui-form-checkbox {
+ margin-right: 5px;
+ margin-bottom: 5px
+ }
+}
+
+.layui-layedit {
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px
+}
+
+.layui-layedit-tool {
+ padding: 3px 5px;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ font-size: 0
+}
+
+.layedit-tool-fixed {
+ position: fixed;
+ top: 0;
+ border-top: 1px solid #eee
+}
+
+.layui-layedit-tool .layedit-tool-mid, .layui-layedit-tool .layui-icon {
+ display: inline-block;
+ vertical-align: middle;
+ text-align: center;
+ font-size: 14px
+}
+
+.layui-layedit-tool .layui-icon {
+ position: relative;
+ width: 32px;
+ height: 30px;
+ line-height: 30px;
+ margin: 3px 5px;
+ color: #777;
+ cursor: pointer;
+ border-radius: 2px
+}
+
+.layui-layedit-tool .layui-icon:hover {
+ color: #393D49
+}
+
+.layui-layedit-tool .layui-icon:active {
+ color: #000
+}
+
+.layui-layedit-tool .layedit-tool-active {
+ background-color: #eee;
+ color: #000
+}
+
+.layui-layedit-tool .layui-disabled, .layui-layedit-tool .layui-disabled:hover {
+ color: #d2d2d2;
+ cursor: not-allowed
+}
+
+.layui-layedit-tool .layedit-tool-mid {
+ width: 1px;
+ height: 18px;
+ margin: 0 10px;
+ background-color: #d2d2d2
+}
+
+.layedit-tool-html {
+ width: 50px !important;
+ font-size: 30px !important
+}
+
+.layedit-tool-b, .layedit-tool-code, .layedit-tool-help {
+ font-size: 16px !important
+}
+
+.layedit-tool-d, .layedit-tool-face, .layedit-tool-image, .layedit-tool-unlink {
+ font-size: 18px !important
+}
+
+.layedit-tool-image input {
+ position: absolute;
+ font-size: 0;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ opacity: .01;
+ filter: Alpha(opacity=1);
+ cursor: pointer
+}
+
+.layui-layedit-iframe iframe {
+ display: block;
+ width: 100%
+}
+
+#LAY_layedit_code {
+ overflow: hidden
+}
+
+.layui-laypage {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle;
+ margin: 10px 0;
+ font-size: 0
+}
+
+.layui-laypage > a:first-child, .layui-laypage > a:first-child em {
+ border-radius: 2px 0 0 2px
+}
+
+.layui-laypage > a:last-child, .layui-laypage > a:last-child em {
+ border-radius: 0 2px 2px 0
+}
+
+.layui-laypage > :first-child {
+ margin-left: 0 !important
+}
+
+.layui-laypage > :last-child {
+ margin-right: 0 !important
+}
+
+.layui-laypage a, .layui-laypage button, .layui-laypage input, .layui-laypage select, .layui-laypage span {
+ border: 1px solid #eee
+}
+
+.layui-laypage a, .layui-laypage span {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle;
+ padding: 0 15px;
+ height: 28px;
+ line-height: 28px;
+ margin: 0 -1px 5px 0;
+ background-color: #fff;
+ color: #333;
+ font-size: 12px
+}
+
+.layui-flow-more a *, .layui-laypage input, .layui-table-view select[lay-ignore] {
+ display: inline-block
+}
+
+.layui-laypage a:hover {
+ color: #009688
+}
+
+.layui-laypage em {
+ font-style: normal
+}
+
+.layui-laypage .layui-laypage-spr {
+ color: #999;
+ font-weight: 700
+}
+
+.layui-laypage a {
+ text-decoration: none
+}
+
+.layui-laypage .layui-laypage-curr {
+ position: relative
+}
+
+.layui-laypage .layui-laypage-curr em {
+ position: relative;
+ color: #fff
+}
+
+.layui-laypage .layui-laypage-curr .layui-laypage-em {
+ position: absolute;
+ left: -1px;
+ top: -1px;
+ padding: 1px;
+ width: 100%;
+ height: 100%;
+ background-color: #009688
+}
+
+.layui-laypage-em {
+ border-radius: 2px
+}
+
+.layui-laypage-next em, .layui-laypage-prev em {
+ font-family: Sim sun;
+ font-size: 16px
+}
+
+.layui-laypage .layui-laypage-count, .layui-laypage .layui-laypage-limits, .layui-laypage .layui-laypage-refresh, .layui-laypage .layui-laypage-skip {
+ margin-left: 10px;
+ margin-right: 10px;
+ padding: 0;
+ border: none
+}
+
+.layui-laypage .layui-laypage-limits, .layui-laypage .layui-laypage-refresh {
+ vertical-align: top
+}
+
+.layui-laypage .layui-laypage-refresh i {
+ font-size: 18px;
+ cursor: pointer
+}
+
+.layui-laypage select {
+ height: 22px;
+ padding: 3px;
+ border-radius: 2px;
+ cursor: pointer
+}
+
+.layui-laypage .layui-laypage-skip {
+ height: 30px;
+ line-height: 30px;
+ color: #999
+}
+
+.layui-laypage button, .layui-laypage input {
+ height: 30px;
+ line-height: 30px;
+ border-radius: 2px;
+ vertical-align: top;
+ background-color: #fff;
+ box-sizing: border-box
+}
+
+.layui-laypage input {
+ width: 40px;
+ margin: 0 10px;
+ padding: 0 3px;
+ text-align: center
+}
+
+.layui-laypage input:focus, .layui-laypage select:focus {
+ border-color: #009688 !important
+}
+
+.layui-laypage button {
+ margin-left: 10px;
+ padding: 0 10px;
+ cursor: pointer
+}
+
+.layui-table, .layui-table-view {
+ /*margin: 10px 0*/
+}
+
+.layui-flow-more {
+ margin: 10px 0;
+ text-align: center;
+ color: #999;
+ font-size: 14px
+}
+
+.layui-flow-more a {
+ height: 32px;
+ line-height: 32px
+}
+
+.layui-flow-more a * {
+ vertical-align: top
+}
+
+.layui-flow-more a cite {
+ padding: 0 20px;
+ border-radius: 3px;
+ background-color: #eee;
+ color: #333;
+ font-style: normal
+}
+
+.layui-flow-more a cite:hover {
+ opacity: .8
+}
+
+.layui-flow-more a i {
+ font-size: 30px;
+ color: #737383
+}
+
+.layui-table {
+ width: 100%;
+ background-color: #fff;
+ color: #666
+}
+
+.layui-table tr {
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-table th {
+ text-align: left;
+ font-weight: 400
+}
+
+.layui-table tbody tr:hover, .layui-table thead tr, .layui-table-click, .layui-table-header, .layui-table-hover, .layui-table-mend, .layui-table-patch, .layui-table-tool, .layui-table-total, .layui-table-total tr, .layui-table[lay-even] tr:nth-child(even) {
+ background-color: #FAFAFA
+}
+
+.layui-table td, .layui-table th, .layui-table-col-set, .layui-table-fixed-r, .layui-table-grid-down, .layui-table-header, .layui-table-page, .layui-table-tips-main, .layui-table-tool, .layui-table-total, .layui-table-view, .layui-table[lay-skin=line], .layui-table[lay-skin=row] {
+ border-width: 1px;
+ border-style: solid;
+ border-color: #eee
+}
+
+.layui-table td, .layui-table th {
+ position: relative;
+ padding: 9px 15px;
+ min-height: 20px;
+ line-height: 20px;
+ font-size: 14px
+}
+
+.layui-table[lay-skin=line] td, .layui-table[lay-skin=line] th {
+ border-width: 0 0 1px
+}
+
+.layui-table[lay-skin=row] td, .layui-table[lay-skin=row] th {
+ border-width: 0 1px 0 0
+}
+
+.layui-table[lay-skin=nob] td, .layui-table[lay-skin=nob] th {
+ border: none
+}
+
+.layui-table img {
+ max-width: 100px
+}
+
+.layui-table[lay-size=lg] td, .layui-table[lay-size=lg] th {
+ padding: 15px 30px
+}
+
+.layui-table-view .layui-table[lay-size=lg] .layui-table-cell {
+ height: 40px;
+ line-height: 40px
+}
+
+.layui-table[lay-size=sm] td, .layui-table[lay-size=sm] th {
+ font-size: 12px;
+ padding: 5px 10px
+}
+
+.layui-table-view .layui-table[lay-size=sm] .layui-table-cell {
+ height: 20px;
+ line-height: 20px
+}
+
+.layui-table[lay-data] {
+ display: none
+}
+
+.layui-table-box {
+ position: relative;
+ overflow: hidden
+}
+
+.layui-table-view .layui-table {
+ position: relative;
+ width: auto;
+ margin: 0
+}
+
+.layui-table-view .layui-table[lay-skin=line] {
+ border-width: 0 1px 0 0
+}
+
+.layui-table-view .layui-table[lay-skin=row] {
+ border-width: 0 0 1px
+}
+
+.layui-table-view .layui-table td, .layui-table-view .layui-table th {
+ padding: 5px 0;
+ border-top: none;
+ border-left: none
+}
+
+.layui-table-view .layui-table th.layui-unselect .layui-table-cell span {
+ cursor: pointer
+}
+
+.layui-table-view .layui-table td {
+ cursor: default
+}
+
+.layui-table-view .layui-table td[data-edit=text] {
+ cursor: text
+}
+
+.layui-table-view .layui-form-checkbox[lay-skin=primary] i {
+ width: 18px;
+ height: 18px
+}
+
+.layui-table-view .layui-form-radio {
+ line-height: 0;
+ padding: 0
+}
+
+.layui-table-view .layui-form-radio > i {
+ margin: 0;
+ font-size: 20px
+}
+
+.layui-table-init {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ text-align: center;
+ z-index: 110
+}
+
+.layui-table-init .layui-icon {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ margin: -15px 0 0 -15px;
+ font-size: 30px;
+ color: #c2c2c2
+}
+
+.layui-table-header {
+ border-width: 0 0 1px;
+ overflow: hidden
+}
+
+.layui-table-header .layui-table {
+ margin-bottom: -1px
+}
+
+.layui-table-tool .layui-inline[lay-event] {
+ position: relative;
+ width: 26px;
+ height: 26px;
+ padding: 5px;
+ line-height: 16px;
+ margin-right: 10px;
+ text-align: center;
+ color: #333;
+ border: 1px solid #ccc;
+ cursor: pointer;
+ -webkit-transition: .5s all;
+ transition: .5s all
+}
+
+.layui-table-tool .layui-inline[lay-event]:hover {
+ border: 1px solid #999
+}
+
+.layui-table-tool-temp {
+ padding-right: 120px
+}
+
+.layui-table-tool-self {
+ position: absolute;
+ right: 17px;
+ top: 10px
+}
+
+.layui-table-tool .layui-table-tool-self .layui-inline[lay-event] {
+ margin: 0 0 0 10px
+}
+
+.layui-table-tool-panel {
+ position: absolute;
+ top: 29px;
+ left: -1px;
+ padding: 5px 0;
+ min-width: 150px;
+ min-height: 40px;
+ border: 1px solid #d2d2d2;
+ text-align: left;
+ overflow-y: auto;
+ background-color: #fff;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12)
+}
+
+.layui-table-cell, .layui-table-tool-panel li {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap
+}
+
+.layui-table-tool-panel li {
+ padding: 0 10px;
+ line-height: 30px;
+ -webkit-transition: .5s all;
+ transition: .5s all
+}
+
+.layui-menu li, .layui-menu-body-title a:hover, .layui-menu-body-title > .layui-icon:hover {
+ transition: all .3s
+}
+
+.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] {
+ width: 100%;
+ padding-left: 28px
+}
+
+.layui-table-tool-panel li:hover {
+ background-color: #F6F6F6
+}
+
+.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] i {
+ position: absolute;
+ left: 0;
+ top: 0
+}
+
+.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] span {
+ padding: 0
+}
+
+.layui-table-tool .layui-table-tool-self .layui-table-tool-panel {
+ left: auto;
+ right: -1px
+}
+
+.layui-table-col-set {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 20px;
+ height: 100%;
+ border-width: 0 0 0 1px;
+ background-color: #fff
+}
+
+.layui-table-sort {
+ width: 10px;
+ height: 20px;
+ margin-left: 5px;
+ cursor: pointer !important
+}
+
+.layui-table-sort .layui-edge {
+ position: absolute;
+ left: 5px;
+ border-width: 5px
+}
+
+.layui-table-sort .layui-table-sort-asc {
+ top: 3px;
+ border-top: none;
+ border-bottom-style: solid;
+ border-bottom-color: #b2b2b2
+}
+
+.layui-table-sort .layui-table-sort-asc:hover {
+ border-bottom-color: #666
+}
+
+.layui-table-sort .layui-table-sort-desc {
+ bottom: 5px;
+ border-bottom: none;
+ border-top-style: solid;
+ border-top-color: #b2b2b2
+}
+
+.layui-table-sort .layui-table-sort-desc:hover {
+ border-top-color: #666
+}
+
+.layui-table-sort[lay-sort=asc] .layui-table-sort-asc {
+ border-bottom-color: #000
+}
+
+.layui-table-sort[lay-sort=desc] .layui-table-sort-desc {
+ border-top-color: #000
+}
+
+.layui-table-cell {
+ height: 28px;
+ line-height: 28px;
+ padding: 0 15px;
+ position: relative;
+ box-sizing: border-box
+}
+
+.layui-table-cell .layui-form-checkbox[lay-skin=primary] {
+ top: -1px;
+ padding: 0
+}
+
+.layui-table-cell .layui-table-link {
+ color: #01AAED
+}
+
+.laytable-cell-checkbox, .laytable-cell-numbers, .laytable-cell-radio, .laytable-cell-space {
+ padding: 0;
+ text-align: center
+}
+
+.layui-table-body {
+ position: relative;
+ overflow: auto;
+ margin-right: -1px;
+ margin-bottom: -1px
+}
+
+.layui-table-body .layui-none {
+ line-height: 26px;
+ padding: 15px;
+ text-align: center;
+ color: #999
+}
+
+.layui-table-fixed {
+ position: absolute;
+ left: 0;
+ top: 0;
+ z-index: 101
+}
+
+.layui-table-fixed .layui-table-body {
+ overflow: hidden
+}
+
+.layui-table-fixed-l {
+ box-shadow: 0 -1px 8px rgba(0, 0, 0, .08)
+}
+
+.layui-table-fixed-r {
+ left: auto;
+ right: -1px;
+ border-width: 0 0 0 1px;
+ box-shadow: -1px 0 8px rgba(0, 0, 0, .08)
+}
+
+.layui-table-fixed-r .layui-table-header {
+ position: relative;
+ overflow: visible
+}
+
+.layui-table-mend {
+ position: absolute;
+ right: -49px;
+ top: 0;
+ height: 100%;
+ width: 50px
+}
+
+.layui-table-tool {
+ position: relative;
+ z-index: 890;
+ width: 100%;
+ min-height: 50px;
+ line-height: 30px;
+ padding: 10px 15px;
+ border-width: 0 0 1px
+}
+
+.layui-table-tool .layui-btn-container {
+ margin-bottom: -10px
+}
+
+.layui-table-page, .layui-table-total {
+ border-width: 1px 0 0;
+ margin-bottom: -1px;
+ overflow: hidden
+}
+
+.layui-table-page {
+ position: relative;
+ width: 100%;
+ padding: 7px 7px 0;
+ height: 41px;
+ font-size: 12px;
+ white-space: nowrap
+}
+
+.layui-table-page > div {
+ height: 26px
+}
+
+.layui-table-page .layui-laypage {
+ margin: 0
+}
+
+.layui-table-page .layui-laypage a, .layui-table-page .layui-laypage span {
+ height: 26px;
+ line-height: 26px;
+ margin-bottom: 10px;
+ border: none;
+ background: 0 0
+}
+
+.layui-table-page .layui-laypage a, .layui-table-page .layui-laypage span.layui-laypage-curr {
+ padding: 0 12px
+}
+
+.layui-table-page .layui-laypage span {
+ margin-left: 0;
+ padding: 0
+}
+
+.layui-table-page .layui-laypage .layui-laypage-prev {
+ margin-left: -7px !important
+}
+
+.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em {
+ left: 0;
+ top: 0;
+ padding: 0
+}
+
+.layui-table-page .layui-laypage button, .layui-table-page .layui-laypage input {
+ height: 26px;
+ line-height: 26px
+}
+
+.layui-table-page .layui-laypage input {
+ width: 40px
+}
+
+.layui-table-page .layui-laypage button {
+ padding: 0 10px
+}
+
+.layui-table-page select {
+ height: 18px
+}
+
+.layui-table-patch .layui-table-cell {
+ padding: 0;
+ width: 30px
+}
+
+.layui-table-edit {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ padding: 0 14px 1px;
+ border-radius: 0;
+ box-shadow: 1px 1px 20px rgba(0, 0, 0, .15)
+}
+
+.layui-table-edit:focus {
+ border-color: #5FB878 !important
+}
+
+select.layui-table-edit {
+ padding: 0 0 0 10px;
+ border-color: #d2d2d2
+}
+
+.layui-table-view .layui-form-checkbox, .layui-table-view .layui-form-radio, .layui-table-view .layui-form-switch {
+ top: 0;
+ margin: 0;
+ box-sizing: content-box
+}
+
+.layui-colorpicker-alpha-slider, .layui-colorpicker-side-slider, .layui-menu, .layui-menu *, .layui-nav {
+ box-sizing: border-box
+}
+
+.layui-table-view .layui-form-checkbox {
+ top: -1px;
+ height: 26px;
+ line-height: 26px
+}
+
+.layui-table-view .layui-form-checkbox i {
+ height: 26px
+}
+
+.layui-table-grid .layui-table-cell {
+ overflow: visible
+}
+
+.layui-table-grid-down {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 26px;
+ height: 100%;
+ padding: 5px 0;
+ border-width: 0 0 0 1px;
+ text-align: center;
+ background-color: #fff;
+ color: #999;
+ cursor: pointer
+}
+
+.layui-table-grid-down .layui-icon {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin: -8px 0 0 -8px
+}
+
+.layui-table-grid-down:hover {
+ background-color: #fbfbfb
+}
+
+body .layui-table-tips .layui-layer-content {
+ background: 0 0;
+ padding: 0;
+ box-shadow: 0 1px 6px rgba(0, 0, 0, .12)
+}
+
+.layui-table-tips-main {
+ margin: -44px 0 0 -1px;
+ max-height: 150px;
+ padding: 8px 15px;
+ font-size: 14px;
+ overflow-y: scroll;
+ background-color: #fff;
+ color: #666
+}
+
+.layui-table-tips-c {
+ position: absolute;
+ right: -3px;
+ top: -13px;
+ width: 20px;
+ height: 20px;
+ padding: 3px;
+ cursor: pointer;
+ background-color: #666;
+ border-radius: 50%;
+ color: #fff
+}
+
+.layui-table-tips-c:hover {
+ background-color: #777
+}
+
+.layui-table-tips-c:before {
+ position: relative;
+ right: -2px
+}
+
+.layui-upload-file {
+ display: none !important;
+ opacity: .01;
+ filter: Alpha(opacity=1)
+}
+
+.layui-upload-drag, .layui-upload-form, .layui-upload-wrap {
+ display: inline-block
+}
+
+.layui-upload-list {
+ margin: 10px 0
+}
+
+.layui-upload-choose {
+ padding: 0 10px;
+ color: #999
+}
+
+.layui-upload-drag {
+ position: relative;
+ padding: 30px;
+ border: 1px dashed #e2e2e2;
+ background-color: #fff;
+ text-align: center;
+ cursor: pointer;
+ color: #999
+}
+
+.layui-upload-drag .layui-icon {
+ font-size: 50px;
+ color: #009688
+}
+
+.layui-upload-drag[lay-over] {
+ border-color: #009688
+}
+
+.layui-upload-iframe {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border: 0;
+ visibility: hidden
+}
+
+.layui-upload-wrap {
+ position: relative;
+ vertical-align: middle
+}
+
+.layui-upload-wrap .layui-upload-file {
+ display: block !important;
+ position: absolute;
+ left: 0;
+ top: 0;
+ z-index: 10;
+ font-size: 100px;
+ width: 100%;
+ height: 100%;
+ opacity: .01;
+ filter: Alpha(opacity=1);
+ cursor: pointer
+}
+
+.layui-menu {
+ position: relative;
+ margin: 5px 0;
+ background-color: #fff
+}
+
+.layui-menu li, .layui-menu-body-title a {
+ padding: 5px 15px
+}
+
+.layui-menu li {
+ position: relative;
+ margin: 1px 0;
+ width: calc(100% + 1px);
+ line-height: 22px;
+ color: rgba(0, 0, 0, .8);
+ font-size: 14px;
+ white-space: nowrap;
+ cursor: pointer
+}
+
+.layui-menu li:hover {
+ background-color: #F6F6F6
+}
+
+.layui-menu-item-parent:hover > .layui-menu-body-panel {
+ display: block;
+ animation-name: layui-fadein;
+ animation-duration: .3s;
+ animation-fill-mode: both;
+ animation-delay: .2s
+}
+
+.layui-menu-item-group .layui-menu-body-title, .layui-menu-item-parent .layui-menu-body-title {
+ padding-right: 25px
+}
+
+.layui-menu .layui-menu-item-divider:hover, .layui-menu .layui-menu-item-group:hover, .layui-menu .layui-menu-item-none:hover {
+ background: 0 0;
+ cursor: default
+}
+
+.layui-menu .layui-menu-item-group > ul {
+ margin: 5px 0 -5px
+}
+
+.layui-menu .layui-menu-item-group > .layui-menu-body-title {
+ color: rgba(0, 0, 0, .35);
+ user-select: none
+}
+
+.layui-menu .layui-menu-item-none {
+ color: rgba(0, 0, 0, .35);
+ cursor: default;
+ text-align: center
+}
+
+.layui-menu .layui-menu-item-divider {
+ margin: 5px 0;
+ padding: 0;
+ height: 0;
+ line-height: 0;
+ border-bottom: 1px solid #eee;
+ overflow: hidden
+}
+
+.layui-menu .layui-menu-item-down:hover, .layui-menu .layui-menu-item-up:hover {
+ cursor: pointer
+}
+
+.layui-menu .layui-menu-item-up > .layui-menu-body-title {
+ color: rgba(0, 0, 0, .8)
+}
+
+.layui-menu .layui-menu-item-up > ul {
+ visibility: hidden;
+ height: 0;
+ overflow: hidden
+}
+
+.layui-menu .layui-menu-item-down:hover > .layui-menu-body-title > .layui-icon, .layui-menu .layui-menu-item-up > .layui-menu-body-title:hover > .layui-icon {
+ color: rgba(0, 0, 0, 1)
+}
+
+.layui-menu .layui-menu-item-down > ul {
+ visibility: visible;
+ height: auto
+}
+
+.layui-breadcrumb, .layui-tree-btnGroup {
+ visibility: hidden
+}
+
+.layui-menu .layui-menu-item-checked, .layui-menu .layui-menu-item-checked2 {
+ background-color: #F6F6F6 !important;
+ color: #5FB878
+}
+
+.layui-menu .layui-menu-item-checked a, .layui-menu .layui-menu-item-checked2 a {
+ color: #5FB878
+}
+
+.layui-menu .layui-menu-item-checked:after {
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ border-right: 3px solid #5FB878;
+ content: ""
+}
+
+.layui-menu-body-title {
+ position: relative;
+ overflow: hidden;
+ text-overflow: ellipsis
+}
+
+.layui-menu-body-title a {
+ display: block;
+ margin: -5px -15px;
+ color: rgba(0, 0, 0, .8)
+}
+
+.layui-menu-body-title > .layui-icon {
+ position: absolute;
+ right: 0;
+ top: 0;
+ font-size: 14px
+}
+
+.layui-menu-body-title > .layui-icon-right {
+ right: -1px
+}
+
+.layui-menu-body-panel {
+ display: none;
+ position: absolute;
+ top: -7px;
+ left: 100%;
+ z-index: 1000;
+ margin-left: 13px;
+ padding: 5px 0
+}
+
+.layui-transfer-active, .layui-transfer-box {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-menu-body-panel:before {
+ content: "";
+ position: absolute;
+ width: 20px;
+ left: -16px;
+ top: 0;
+ bottom: 0
+}
+
+.layui-menu-body-panel-left {
+ left: auto;
+ right: 100%;
+ margin: 0 13px
+}
+
+.layui-menu-body-panel-left:before {
+ left: auto;
+ right: -16px
+}
+
+.layui-menu-lg li {
+ line-height: 32px
+}
+
+.layui-menu-lg .layui-menu-body-title a:hover, .layui-menu-lg li:hover {
+ background: 0 0;
+ color: #5FB878
+}
+
+.layui-menu-lg li .layui-menu-body-panel {
+ margin-left: 14px
+}
+
+.layui-menu-lg li .layui-menu-body-panel-left {
+ margin: 0 15px
+}
+
+.layui-dropdown {
+ position: absolute;
+ left: -999999px;
+ top: -999999px;
+ z-index: 66666666;
+ margin: 5px 0;
+ min-width: 100px
+}
+
+.layui-dropdown:before {
+ content: "";
+ position: absolute;
+ width: 100%;
+ height: 6px;
+ left: 0;
+ top: -6px
+}
+
+.layui-transfer-box, .layui-transfer-header, .layui-transfer-search {
+ border-width: 0;
+ border-style: solid;
+ border-color: #eee
+}
+
+.layui-transfer-box {
+ position: relative;
+ border-width: 1px;
+ width: 200px;
+ height: 360px;
+ border-radius: 2px;
+ background-color: #fff
+}
+
+.layui-transfer-box .layui-form-checkbox {
+ width: 100%;
+ margin: 0 !important
+}
+
+.layui-transfer-header {
+ height: 38px;
+ line-height: 38px;
+ padding: 0 10px;
+ border-bottom-width: 1px
+}
+
+.layui-transfer-search {
+ position: relative;
+ padding: 10px;
+ border-bottom-width: 1px
+}
+
+.layui-transfer-search .layui-input {
+ height: 32px;
+ padding-left: 30px;
+ font-size: 12px
+}
+
+.layui-transfer-search .layui-icon-search {
+ position: absolute;
+ left: 20px;
+ top: 50%;
+ margin-top: -8px;
+ color: #666
+}
+
+.layui-transfer-active {
+ margin: 0 15px
+}
+
+.layui-transfer-active .layui-btn {
+ display: block;
+ margin: 0;
+ padding: 0 15px;
+ background-color: #5FB878;
+ border-color: #5FB878;
+ color: #fff
+}
+
+.layui-transfer-active .layui-btn-disabled {
+ background-color: #FBFBFB;
+ border-color: #eee;
+ color: #d2d2d2
+}
+
+.layui-transfer-active .layui-btn:first-child {
+ margin-bottom: 15px
+}
+
+.layui-transfer-active .layui-btn .layui-icon {
+ margin: 0;
+ font-size: 14px !important
+}
+
+.layui-transfer-data {
+ padding: 5px 0;
+ overflow: auto
+}
+
+.layui-transfer-data li {
+ height: 32px;
+ line-height: 32px;
+ padding: 0 10px
+}
+
+.layui-transfer-data li:hover {
+ background-color: #F6F6F6;
+ transition: .5s all
+}
+
+.layui-transfer-data .layui-none {
+ padding: 15px 10px;
+ text-align: center;
+ color: #999
+}
+
+.layui-nav {
+ position: relative;
+ padding: 0 20px;
+ background-color: #393D49;
+ color: #fff;
+ border-radius: 2px;
+ font-size: 0
+}
+
+.layui-nav * {
+ font-size: 14px
+}
+
+.layui-nav .layui-nav-item {
+ position: relative;
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle;
+ line-height: 60px
+}
+
+.layui-nav .layui-nav-item a {
+ display: block;
+ padding: 0 20px;
+ color: #fff;
+ color: rgba(255, 255, 255, .7);
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-nav .layui-this:after, .layui-nav-bar, .layui-nav-tree .layui-nav-itemed:after {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 0;
+ height: 5px;
+ background-color: #5FB878;
+ transition: all .2s;
+ -webkit-transition: all .2s
+}
+
+.layui-nav-bar {
+ z-index: 1000
+}
+
+.layui-nav .layui-nav-item a:hover, .layui-nav .layui-this a {
+ color: #fff
+}
+
+.layui-nav .layui-this:after {
+ content: "";
+ top: auto;
+ bottom: 0;
+ width: 100%
+}
+
+.layui-nav-img {
+ width: 30px;
+ height: 30px;
+ margin-right: 10px;
+ border-radius: 50%
+}
+
+.layui-nav .layui-nav-more {
+ content: "";
+ width: 0;
+ height: 0;
+ border-style: solid dashed dashed;
+ border-color: #fff transparent transparent;
+ overflow: hidden;
+ cursor: pointer;
+ transition: all .2s;
+ -webkit-transition: all .2s;
+ position: absolute;
+ top: 50%;
+ right: 3px;
+ margin-top: -4px;
+ border-width: 6px;
+ border-top-color: rgba(255, 255, 255, .7)
+}
+
+.layui-nav .layui-nav-mored, .layui-nav-itemed > a .layui-nav-more {
+ margin-top: -9px;
+ border-style: dashed dashed solid;
+ border-color: transparent transparent #fff
+}
+
+.layui-nav-child {
+ display: none;
+ position: absolute;
+ left: 0;
+ top: 65px;
+ min-width: 100%;
+ line-height: 36px;
+ padding: 5px 0;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12);
+ border: 1px solid #d2d2d2;
+ background-color: #fff;
+ z-index: 100;
+ border-radius: 2px;
+ white-space: nowrap
+}
+
+.layui-nav .layui-nav-child a {
+ color: #333
+}
+
+.layui-nav .layui-nav-child a:hover {
+ background-color: #F6F6F6;
+ color: #5FB878
+}
+
+.layui-nav-child dd {
+ position: relative
+}
+
+.layui-nav .layui-nav-child dd.layui-this a, .layui-nav-child dd.layui-this {
+ background-color: #5FB878;
+ color: #fff
+}
+
+.layui-nav-child dd.layui-this:after {
+ display: none
+}
+
+.layui-nav-tree {
+ width: 200px;
+ padding: 0
+}
+
+.layui-nav-tree .layui-nav-item {
+ display: block;
+ width: 100%;
+ line-height: 45px
+}
+
+.layui-nav-tree .layui-nav-item a {
+ position: relative;
+ height: 45px;
+ line-height: 45px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap
+}
+
+.layui-nav-tree .layui-nav-item a:hover {
+ background-color: #4E5465
+}
+
+.layui-nav-tree .layui-nav-bar {
+ width: 5px;
+ height: 0;
+ background-color: #009688
+}
+
+.layui-nav-tree .layui-nav-child dd.layui-this, .layui-nav-tree .layui-nav-child dd.layui-this a, .layui-nav-tree .layui-this, .layui-nav-tree .layui-this > a, .layui-nav-tree .layui-this > a:hover {
+ background-color: #009688;
+ color: #fff
+}
+
+.layui-nav-tree .layui-this:after {
+ display: none
+}
+
+.layui-nav-itemed > a, .layui-nav-tree .layui-nav-title a, .layui-nav-tree .layui-nav-title a:hover {
+ color: #fff !important
+}
+
+.layui-nav-tree .layui-nav-child {
+ position: relative;
+ z-index: 0;
+ top: 0;
+ border: none;
+ box-shadow: none
+}
+
+.layui-nav-tree .layui-nav-child a {
+ height: 40px;
+ line-height: 40px;
+ color: #fff;
+ color: rgba(255, 255, 255, .7)
+}
+
+.layui-nav-tree .layui-nav-child, .layui-nav-tree .layui-nav-child a:hover {
+ background: 0 0;
+ color: #fff
+}
+
+.layui-nav-tree .layui-nav-more {
+ right: 10px
+}
+
+.layui-nav-itemed > .layui-nav-child {
+ display: block;
+ padding: 0;
+ background-color: rgba(0, 0, 0, .3) !important
+}
+
+.layui-nav-itemed > .layui-nav-child > .layui-this > .layui-nav-child {
+ display: block
+}
+
+.layui-nav-side {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ overflow-x: hidden;
+ z-index: 999
+}
+
+.layui-bg-blue .layui-nav-bar, .layui-bg-blue .layui-nav-itemed:after, .layui-bg-blue .layui-this:after {
+ background-color: #93D1FF
+}
+
+.layui-bg-blue .layui-nav-child dd.layui-this {
+ background-color: #1E9FFF
+}
+
+.layui-bg-blue .layui-nav-itemed > a, .layui-nav-tree.layui-bg-blue .layui-nav-title a, .layui-nav-tree.layui-bg-blue .layui-nav-title a:hover {
+ background-color: #007DDB !important
+}
+
+.layui-breadcrumb {
+ font-size: 0
+}
+
+.layui-breadcrumb > * {
+ font-size: 14px
+}
+
+.layui-breadcrumb a {
+ color: #999 !important
+}
+
+.layui-breadcrumb a:hover {
+ color: #5FB878 !important
+}
+
+.layui-breadcrumb a cite {
+ color: #666;
+ font-style: normal
+}
+
+.layui-breadcrumb span[lay-separator] {
+ margin: 0 10px;
+ color: #999
+}
+
+.layui-tab {
+ margin: 10px 0;
+ text-align: left !important
+}
+
+.layui-tab[overflow] > .layui-tab-title {
+ overflow: hidden
+}
+
+.layui-tab-title {
+ position: relative;
+ left: 0;
+ height: 40px;
+ white-space: nowrap;
+ font-size: 0;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ transition: all .2s;
+ -webkit-transition: all .2s
+}
+
+.layui-tab-title li {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle;
+ font-size: 14px;
+ transition: all .2s;
+ -webkit-transition: all .2s;
+ position: relative;
+ line-height: 40px;
+ min-width: 65px;
+ padding: 0 15px;
+ text-align: center;
+ cursor: pointer
+}
+
+.layui-tab-title li a {
+ display: block
+}
+
+.layui-tab-title .layui-this {
+ color: #000
+}
+
+.layui-tab-title .layui-this:after {
+ position: absolute;
+ left: 0;
+ top: 0;
+ content: "";
+ width: 100%;
+ height: 41px;
+ border-width: 1px;
+ border-style: solid;
+ border-bottom-color: #fff;
+ border-radius: 2px 2px 0 0;
+ box-sizing: border-box;
+ pointer-events: none
+}
+
+.layui-tab-bar {
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: 10;
+ width: 30px;
+ height: 39px;
+ line-height: 39px;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px;
+ text-align: center;
+ background-color: #fff;
+ cursor: pointer
+}
+
+.layui-tab-bar .layui-icon {
+ position: relative;
+ display: inline-block;
+ top: 3px;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-tab-item {
+ display: none
+}
+
+.layui-tab-more {
+ padding-right: 30px;
+ height: auto !important;
+ white-space: normal !important
+}
+
+.layui-tab-more li.layui-this:after {
+ border-bottom-color: #eee;
+ border-radius: 2px
+}
+
+.layui-tab-more .layui-tab-bar .layui-icon {
+ top: -2px;
+ top: 3px \9;
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg)
+}
+
+:root .layui-tab-more .layui-tab-bar .layui-icon {
+ top: -2px \0/ IE9
+}
+
+.layui-tab-content {
+ padding: 15px 0
+}
+
+.layui-tab-title li .layui-tab-close {
+ position: relative;
+ display: inline-block;
+ width: 18px;
+ height: 18px;
+ line-height: 20px;
+ margin-left: 8px;
+ top: 1px;
+ text-align: center;
+ font-size: 14px;
+ color: #c2c2c2;
+ transition: all .2s;
+ -webkit-transition: all .2s
+}
+
+.layui-tab-title li .layui-tab-close:hover {
+ border-radius: 2px;
+ background-color: #FF5722;
+ color: #fff
+}
+
+.layui-tab-brief > .layui-tab-title .layui-this {
+ color: #009688
+}
+
+.layui-tab-brief > .layui-tab-more li.layui-this:after, .layui-tab-brief > .layui-tab-title .layui-this:after {
+ border: none;
+ border-radius: 0;
+ border-bottom: 2px solid #5FB878
+}
+
+.layui-tab-brief[overflow] > .layui-tab-title .layui-this:after {
+ top: -1px
+}
+
+.layui-tab-card {
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
+}
+
+.layui-tab-card > .layui-tab-title {
+ background-color: #FAFAFA
+}
+
+.layui-tab-card > .layui-tab-title li {
+ margin-right: -1px;
+ margin-left: -1px
+}
+
+.layui-tab-card > .layui-tab-title .layui-this {
+ background-color: #fff
+}
+
+.layui-tab-card > .layui-tab-title .layui-this:after {
+ border-top: none;
+ border-width: 1px;
+ border-bottom-color: #fff
+}
+
+.layui-tab-card > .layui-tab-title .layui-tab-bar {
+ height: 40px;
+ line-height: 40px;
+ border-radius: 0;
+ border-top: none;
+ border-right: none
+}
+
+.layui-tab-card > .layui-tab-more .layui-this {
+ background: 0 0;
+ color: #5FB878
+}
+
+.layui-tab-card > .layui-tab-more .layui-this:after {
+ border: none
+}
+
+.layui-timeline {
+ padding-left: 5px
+}
+
+.layui-timeline-item {
+ position: relative;
+ padding-bottom: 20px
+}
+
+.layui-timeline-axis {
+ position: absolute;
+ left: -5px;
+ top: 0;
+ z-index: 10;
+ width: 20px;
+ height: 20px;
+ line-height: 20px;
+ background-color: #fff;
+ color: #5FB878;
+ border-radius: 50%;
+ text-align: center;
+ cursor: pointer
+}
+
+.layui-timeline-axis:hover {
+ color: #FF5722
+}
+
+.layui-timeline-item:before {
+ content: "";
+ position: absolute;
+ left: 5px;
+ top: 0;
+ z-index: 0;
+ width: 1px;
+ height: 100%
+}
+
+.layui-timeline-item:first-child:before {
+ display: block
+}
+
+.layui-timeline-item:last-child:before {
+ display: none
+}
+
+.layui-timeline-content {
+ padding-left: 25px
+}
+
+.layui-timeline-title {
+ position: relative;
+ margin-bottom: 10px;
+ line-height: 22px
+}
+
+.layui-badge, .layui-badge-dot, .layui-badge-rim {
+ position: relative;
+ display: inline-block;
+ padding: 0 6px;
+ font-size: 12px;
+ text-align: center;
+ background-color: #FF5722;
+ color: #fff;
+ border-radius: 2px
+}
+
+.layui-badge {
+ height: 18px;
+ line-height: 18px
+}
+
+.layui-badge-dot {
+ width: 8px;
+ height: 8px;
+ padding: 0;
+ border-radius: 50%
+}
+
+.layui-badge-rim {
+ height: 18px;
+ line-height: 18px;
+ border-width: 1px;
+ border-style: solid;
+ background-color: #fff;
+ color: #666
+}
+
+.layui-btn .layui-badge, .layui-btn .layui-badge-dot {
+ margin-left: 5px
+}
+
+.layui-nav .layui-badge, .layui-nav .layui-badge-dot {
+ position: absolute;
+ top: 50%;
+ margin: -5px 6px 0
+}
+
+.layui-nav .layui-badge {
+ margin-top: -10px
+}
+
+.layui-tab-title .layui-badge, .layui-tab-title .layui-badge-dot {
+ left: 5px;
+ top: -2px
+}
+
+.layui-carousel {
+ position: relative;
+ left: 0;
+ top: 0;
+ background-color: #f8f8f8
+}
+
+.layui-carousel > [carousel-item] {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ overflow: hidden
+}
+
+.layui-carousel > [carousel-item]:before {
+ position: absolute;
+ content: '\e63d';
+ left: 50%;
+ top: 50%;
+ width: 100px;
+ line-height: 20px;
+ margin: -10px 0 0 -50px;
+ text-align: center;
+ color: #c2c2c2;
+ font-family: layui-icon !important;
+ font-size: 30px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale
+}
+
+.layui-carousel > [carousel-item] > * {
+ display: none;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: #f8f8f8;
+ transition-duration: .3s;
+ -webkit-transition-duration: .3s
+}
+
+.layui-carousel-updown > * {
+ -webkit-transition: .3s ease-in-out up;
+ transition: .3s ease-in-out up
+}
+
+.layui-carousel-arrow {
+ display: none \9;
+ opacity: 0;
+ position: absolute;
+ left: 10px;
+ top: 50%;
+ margin-top: -18px;
+ width: 36px;
+ height: 36px;
+ line-height: 36px;
+ text-align: center;
+ font-size: 20px;
+ border: 0;
+ border-radius: 50%;
+ background-color: rgba(0, 0, 0, .2);
+ color: #fff;
+ -webkit-transition-duration: .3s;
+ transition-duration: .3s;
+ cursor: pointer
+}
+
+.layui-carousel-arrow[lay-type=add] {
+ left: auto !important;
+ right: 10px
+}
+
+.layui-carousel:hover .layui-carousel-arrow[lay-type=add], .layui-carousel[lay-arrow=always] .layui-carousel-arrow[lay-type=add] {
+ right: 20px
+}
+
+.layui-carousel[lay-arrow=always] .layui-carousel-arrow {
+ opacity: 1;
+ left: 20px
+}
+
+.layui-carousel[lay-arrow=none] .layui-carousel-arrow {
+ display: none
+}
+
+.layui-carousel-arrow:hover, .layui-carousel-ind ul:hover {
+ background-color: rgba(0, 0, 0, .35)
+}
+
+.layui-carousel:hover .layui-carousel-arrow {
+ display: block \9;
+ opacity: 1;
+ left: 20px
+}
+
+.layui-carousel-ind {
+ position: relative;
+ top: -35px;
+ width: 100%;
+ line-height: 0 !important;
+ text-align: center;
+ font-size: 0
+}
+
+.layui-carousel[lay-indicator=outside] {
+ margin-bottom: 30px
+}
+
+.layui-carousel[lay-indicator=outside] .layui-carousel-ind {
+ top: 10px
+}
+
+.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul {
+ background-color: rgba(0, 0, 0, .5)
+}
+
+.layui-carousel[lay-indicator=none] .layui-carousel-ind {
+ display: none
+}
+
+.layui-carousel-ind ul {
+ display: inline-block;
+ padding: 5px;
+ background-color: rgba(0, 0, 0, .2);
+ border-radius: 10px;
+ -webkit-transition-duration: .3s;
+ transition-duration: .3s
+}
+
+.layui-carousel-ind li {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ margin: 0 3px;
+ font-size: 14px;
+ background-color: #eee;
+ background-color: rgba(255, 255, 255, .5);
+ border-radius: 50%;
+ cursor: pointer;
+ -webkit-transition-duration: .3s;
+ transition-duration: .3s
+}
+
+.layui-carousel-ind li:hover {
+ background-color: rgba(255, 255, 255, .7)
+}
+
+.layui-carousel-ind li.layui-this {
+ background-color: #fff
+}
+
+.layui-carousel > [carousel-item] > .layui-carousel-next, .layui-carousel > [carousel-item] > .layui-carousel-prev, .layui-carousel > [carousel-item] > .layui-this {
+ display: block
+}
+
+.layui-carousel > [carousel-item] > .layui-this {
+ left: 0
+}
+
+.layui-carousel > [carousel-item] > .layui-carousel-prev {
+ left: -100%
+}
+
+.layui-carousel > [carousel-item] > .layui-carousel-next {
+ left: 100%
+}
+
+.layui-carousel > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel > [carousel-item] > .layui-carousel-prev.layui-carousel-right {
+ left: 0
+}
+
+.layui-carousel > [carousel-item] > .layui-this.layui-carousel-left {
+ left: -100%
+}
+
+.layui-carousel > [carousel-item] > .layui-this.layui-carousel-right {
+ left: 100%
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-arrow {
+ left: 50% !important;
+ top: 20px;
+ margin: 0 0 0 -18px
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > *, .layui-carousel[lay-anim=fade] > [carousel-item] > * {
+ left: 0 !important
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-arrow[lay-type=add] {
+ top: auto !important;
+ bottom: 20px
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-ind {
+ position: absolute;
+ top: 50%;
+ right: 20px;
+ width: auto;
+ height: auto
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-ind ul {
+ padding: 3px 5px
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-ind li {
+ display: block;
+ margin: 6px 0
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this {
+ top: 0
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-prev {
+ top: -100%
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-next {
+ top: 100%
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-prev.layui-carousel-right {
+ top: 0
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this.layui-carousel-left {
+ top: -100%
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this.layui-carousel-right {
+ top: 100%
+}
+
+.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-next, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-prev {
+ opacity: 0
+}
+
+.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-prev.layui-carousel-right {
+ opacity: 1
+}
+
+.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-this.layui-carousel-left, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-this.layui-carousel-right {
+ opacity: 0
+}
+
+.layui-fixbar {
+ position: fixed;
+ right: 15px;
+ bottom: 15px;
+ z-index: 999999
+}
+
+.layui-fixbar li {
+ width: 50px;
+ height: 50px;
+ line-height: 50px;
+ margin-bottom: 1px;
+ text-align: center;
+ cursor: pointer;
+ font-size: 30px;
+ background-color: #9F9F9F;
+ color: #fff;
+ border-radius: 2px;
+ opacity: .95
+}
+
+.layui-fixbar li:hover {
+ opacity: .85
+}
+
+.layui-fixbar li:active {
+ opacity: 1
+}
+
+.layui-fixbar .layui-fixbar-top {
+ display: none;
+ font-size: 40px
+}
+
+body .layui-util-face {
+ border: none;
+ background: 0 0
+}
+
+body .layui-util-face .layui-layer-content {
+ padding: 0;
+ background-color: #fff;
+ color: #666;
+ box-shadow: none
+}
+
+.layui-util-face .layui-layer-TipsG {
+ display: none
+}
+
+.layui-util-face ul {
+ position: relative;
+ width: 372px;
+ padding: 10px;
+ border: 1px solid #D9D9D9;
+ background-color: #fff;
+ box-shadow: 0 0 20px rgba(0, 0, 0, .2)
+}
+
+.layui-util-face ul li {
+ cursor: pointer;
+ float: left;
+ border: 1px solid #e8e8e8;
+ height: 22px;
+ width: 26px;
+ overflow: hidden;
+ margin: -1px 0 0 -1px;
+ padding: 4px 2px;
+ text-align: center
+}
+
+.layui-util-face ul li:hover {
+ position: relative;
+ z-index: 2;
+ border: 1px solid #eb7350;
+ background: #fff9ec
+}
+
+.layui-code {
+ position: relative;
+ margin: 10px 0;
+ padding: 15px;
+ line-height: 20px;
+ border: 1px solid #eee;
+ border-left-width: 6px;
+ background-color: #FAFAFA;
+ color: #333;
+ font-family: Courier New;
+ font-size: 12px
+}
+
+.layui-rate, .layui-rate * {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-rate {
+ padding: 10px 5px 10px 0;
+ font-size: 0
+}
+
+.layui-rate li i.layui-icon {
+ font-size: 20px;
+ color: #FFB800;
+ margin-right: 5px;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-rate li i:hover {
+ cursor: pointer;
+ transform: scale(1.12);
+ -webkit-transform: scale(1.12)
+}
+
+.layui-rate[readonly] li i:hover {
+ cursor: default;
+ transform: scale(1)
+}
+
+.layui-colorpicker {
+ width: 26px;
+ height: 26px;
+ border: 1px solid #eee;
+ padding: 5px;
+ border-radius: 2px;
+ line-height: 24px;
+ display: inline-block;
+ cursor: pointer;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-colorpicker:hover {
+ border-color: #d2d2d2
+}
+
+.layui-colorpicker.layui-colorpicker-lg {
+ width: 34px;
+ height: 34px;
+ line-height: 32px
+}
+
+.layui-colorpicker.layui-colorpicker-sm {
+ width: 24px;
+ height: 24px;
+ line-height: 22px
+}
+
+.layui-colorpicker.layui-colorpicker-xs {
+ width: 22px;
+ height: 22px;
+ line-height: 20px
+}
+
+.layui-colorpicker-trigger-bgcolor {
+ display: block;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
+ border-radius: 2px
+}
+
+.layui-colorpicker-trigger-span {
+ display: block;
+ height: 100%;
+ box-sizing: border-box;
+ border: 1px solid rgba(0, 0, 0, .15);
+ border-radius: 2px;
+ text-align: center
+}
+
+.layui-colorpicker-trigger-i {
+ display: inline-block;
+ color: #FFF;
+ font-size: 12px
+}
+
+.layui-colorpicker-trigger-i.layui-icon-close {
+ color: #999
+}
+
+.layui-colorpicker-main {
+ position: absolute;
+ z-index: 66666666;
+ width: 280px;
+ padding: 7px;
+ background: #FFF;
+ border: 1px solid #d2d2d2;
+ border-radius: 2px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12)
+}
+
+.layui-colorpicker-main-wrapper {
+ height: 180px;
+ position: relative
+}
+
+.layui-colorpicker-basis {
+ width: 260px;
+ height: 100%;
+ position: relative
+}
+
+.layui-colorpicker-basis-white {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ background: linear-gradient(90deg, #FFF, hsla(0, 0%, 100%, 0))
+}
+
+.layui-colorpicker-basis-black {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ background: linear-gradient(0deg, #000, transparent)
+}
+
+.layui-colorpicker-basis-cursor {
+ width: 10px;
+ height: 10px;
+ border: 1px solid #FFF;
+ border-radius: 50%;
+ position: absolute;
+ top: -3px;
+ right: -3px;
+ cursor: pointer
+}
+
+.layui-colorpicker-side {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 12px;
+ height: 100%;
+ background: linear-gradient(red, #FF0, #0F0, #0FF, #00F, #F0F, red)
+}
+
+.layui-colorpicker-side-slider {
+ width: 100%;
+ height: 5px;
+ box-shadow: 0 0 1px #888;
+ background: #FFF;
+ border-radius: 1px;
+ border: 1px solid #f0f0f0;
+ cursor: pointer;
+ position: absolute;
+ left: 0
+}
+
+.layui-colorpicker-main-alpha {
+ display: none;
+ height: 12px;
+ margin-top: 7px;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)
+}
+
+.layui-colorpicker-alpha-bgcolor {
+ height: 100%;
+ position: relative
+}
+
+.layui-colorpicker-alpha-slider {
+ width: 5px;
+ height: 100%;
+ box-shadow: 0 0 1px #888;
+ background: #FFF;
+ border-radius: 1px;
+ border: 1px solid #f0f0f0;
+ cursor: pointer;
+ position: absolute;
+ top: 0
+}
+
+.layui-colorpicker-main-pre {
+ padding-top: 7px;
+ font-size: 0
+}
+
+.layui-colorpicker-pre {
+ width: 20px;
+ height: 20px;
+ border-radius: 2px;
+ display: inline-block;
+ margin-left: 6px;
+ margin-bottom: 7px;
+ cursor: pointer
+}
+
+.layui-colorpicker-pre:nth-child(11n+1) {
+ margin-left: 0
+}
+
+.layui-colorpicker-pre-isalpha {
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)
+}
+
+.layui-colorpicker-pre.layui-this {
+ box-shadow: 0 0 3px 2px rgba(0, 0, 0, .15)
+}
+
+.layui-colorpicker-pre > div {
+ height: 100%;
+ border-radius: 2px
+}
+
+.layui-colorpicker-main-input {
+ text-align: right;
+ padding-top: 7px
+}
+
+.layui-colorpicker-main-input .layui-btn-container .layui-btn {
+ margin: 0 0 0 10px
+}
+
+.layui-colorpicker-main-input div.layui-inline {
+ float: left;
+ margin-right: 10px;
+ font-size: 14px
+}
+
+.layui-colorpicker-main-input input.layui-input {
+ width: 150px;
+ height: 30px;
+ color: #666
+}
+
+.layui-slider {
+ height: 4px;
+ background: #eee;
+ border-radius: 3px;
+ position: relative;
+ cursor: pointer
+}
+
+.layui-slider-bar {
+ border-radius: 3px;
+ position: absolute;
+ height: 100%
+}
+
+.layui-slider-step {
+ position: absolute;
+ top: 0;
+ width: 4px;
+ height: 4px;
+ border-radius: 50%;
+ background: #FFF;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%)
+}
+
+.layui-slider-wrap {
+ width: 36px;
+ height: 36px;
+ position: absolute;
+ top: -16px;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%);
+ z-index: 10;
+ text-align: center
+}
+
+.layui-slider-wrap-btn {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ background: #FFF;
+ display: inline-block;
+ vertical-align: middle;
+ cursor: pointer;
+ transition: .3s
+}
+
+.layui-slider-wrap:after {
+ content: "";
+ height: 100%;
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-slider-wrap-btn.layui-slider-hover, .layui-slider-wrap-btn:hover {
+ transform: scale(1.2)
+}
+
+.layui-slider-wrap-btn.layui-disabled:hover {
+ transform: scale(1) !important
+}
+
+.layui-slider-tips {
+ position: absolute;
+ top: -42px;
+ z-index: 66666666;
+ white-space: nowrap;
+ display: none;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%);
+ color: #FFF;
+ background: #000;
+ border-radius: 3px;
+ height: 25px;
+ line-height: 25px;
+ padding: 0 10px
+}
+
+.layui-slider-tips:after {
+ content: "";
+ position: absolute;
+ bottom: -12px;
+ left: 50%;
+ margin-left: -6px;
+ width: 0;
+ height: 0;
+ border-width: 6px;
+ border-style: solid;
+ border-color: #000 transparent transparent
+}
+
+.layui-slider-input {
+ width: 70px;
+ height: 32px;
+ border: 1px solid #eee;
+ border-radius: 3px;
+ font-size: 16px;
+ line-height: 32px;
+ position: absolute;
+ right: 0;
+ top: -14px
+}
+
+.layui-slider-input-btn {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 20px;
+ height: 100%;
+ border-left: 1px solid #eee
+}
+
+.layui-slider-input-btn i {
+ cursor: pointer;
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ width: 20px;
+ height: 50%;
+ font-size: 12px;
+ line-height: 16px;
+ text-align: center;
+ color: #999
+}
+
+.layui-slider-input-btn i:first-child {
+ top: 0;
+ border-bottom: 1px solid #eee
+}
+
+.layui-slider-input-txt {
+ height: 100%;
+ font-size: 14px
+}
+
+.layui-slider-input-txt input {
+ height: 100%;
+ border: none
+}
+
+.layui-slider-input-btn i:hover {
+ color: #009688
+}
+
+.layui-slider-vertical {
+ width: 4px;
+ margin-left: 33px
+}
+
+.layui-slider-vertical .layui-slider-bar {
+ width: 4px
+}
+
+.layui-slider-vertical .layui-slider-step {
+ top: auto;
+ left: 0;
+ -webkit-transform: translateY(50%);
+ transform: translateY(50%)
+}
+
+.layui-slider-vertical .layui-slider-wrap {
+ top: auto;
+ left: -16px;
+ -webkit-transform: translateY(50%);
+ transform: translateY(50%)
+}
+
+.layui-slider-vertical .layui-slider-tips {
+ top: auto;
+ left: 2px
+}
+
+@media \0screen {
+ .layui-slider-wrap-btn {
+ margin-left: -20px
+ }
+
+ .layui-slider-vertical .layui-slider-wrap-btn {
+ margin-left: 0;
+ margin-bottom: -20px
+ }
+
+ .layui-slider-vertical .layui-slider-tips {
+ margin-left: -8px
+ }
+
+ .layui-slider > span {
+ margin-left: 8px
+ }
+}
+
+.layui-tree {
+ line-height: 22px
+}
+
+.layui-tree .layui-form-checkbox {
+ margin: 0 !important
+}
+
+.layui-tree-set {
+ width: 100%;
+ position: relative
+}
+
+.layui-tree-pack {
+ display: none;
+ padding-left: 20px;
+ position: relative
+}
+
+.layui-tree-iconClick, .layui-tree-main {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-tree-line .layui-tree-pack {
+ padding-left: 27px
+}
+
+.layui-tree-line .layui-tree-set .layui-tree-set:after {
+ content: "";
+ position: absolute;
+ top: 14px;
+ left: -9px;
+ width: 17px;
+ height: 0;
+ border-top: 1px dotted #c0c4cc
+}
+
+.layui-tree-entry {
+ position: relative;
+ padding: 3px 0;
+ height: 20px;
+ white-space: nowrap
+}
+
+.layui-tree-entry:hover {
+ background-color: #eee
+}
+
+.layui-tree-line .layui-tree-entry:hover {
+ background-color: rgba(0, 0, 0, 0)
+}
+
+.layui-tree-line .layui-tree-entry:hover .layui-tree-txt {
+ color: #999;
+ text-decoration: underline;
+ transition: .3s
+}
+
+.layui-tree-main {
+ cursor: pointer;
+ padding-right: 10px
+}
+
+.layui-tree-line .layui-tree-set:before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: -9px;
+ width: 0;
+ height: 100%;
+ border-left: 1px dotted #c0c4cc
+}
+
+.layui-tree-line .layui-tree-set.layui-tree-setLineShort:before {
+ height: 13px
+}
+
+.layui-tree-line .layui-tree-set.layui-tree-setHide:before {
+ height: 0
+}
+
+.layui-tree-iconClick {
+ position: relative;
+ height: 20px;
+ line-height: 20px;
+ margin: 0 10px;
+ color: #c0c4cc
+}
+
+.layui-tree-icon {
+ height: 12px;
+ line-height: 12px;
+ width: 12px;
+ text-align: center;
+ border: 1px solid #c0c4cc
+}
+
+.layui-tree-iconClick .layui-icon {
+ font-size: 18px
+}
+
+.layui-tree-icon .layui-icon {
+ font-size: 12px;
+ color: #666
+}
+
+.layui-tree-iconArrow {
+ padding: 0 5px
+}
+
+.layui-tree-iconArrow:after {
+ content: "";
+ position: absolute;
+ left: 4px;
+ top: 3px;
+ z-index: 100;
+ width: 0;
+ height: 0;
+ border-width: 5px;
+ border-style: solid;
+ border-color: transparent transparent transparent #c0c4cc;
+ transition: .5s
+}
+
+.layui-tree-btnGroup, .layui-tree-editInput {
+ position: relative;
+ vertical-align: middle;
+ display: inline-block
+}
+
+.layui-tree-spread > .layui-tree-entry > .layui-tree-iconClick > .layui-tree-iconArrow:after {
+ transform: rotate(90deg) translate(3px, 4px)
+}
+
+.layui-tree-txt {
+ display: inline-block;
+ vertical-align: middle;
+ color: #555
+}
+
+.layui-tree-search {
+ margin-bottom: 15px;
+ color: #666
+}
+
+.layui-tree-btnGroup .layui-icon {
+ display: inline-block;
+ vertical-align: middle;
+ padding: 0 2px;
+ cursor: pointer
+}
+
+.layui-tree-btnGroup .layui-icon:hover {
+ color: #999;
+ transition: .3s
+}
+
+.layui-tree-entry:hover .layui-tree-btnGroup {
+ visibility: visible
+}
+
+.layui-tree-editInput {
+ height: 20px;
+ line-height: 20px;
+ padding: 0 3px;
+ border: none;
+ background-color: rgba(0, 0, 0, .05)
+}
+
+.layui-tree-emptyText {
+ text-align: center;
+ color: #999
+}
+
+.layui-anim {
+ -webkit-animation-duration: .2s;
+ -webkit-animation-fill-mode: both;
+ animation-duration: .2s;
+ animation-fill-mode: both
+}
+
+.layui-anim.layui-icon {
+ display: inline-block
+}
+
+.layui-anim-loop {
+ -webkit-animation-iteration-count: infinite;
+ animation-iteration-count: infinite
+}
+
+.layui-trans, .layui-trans a {
+ transition: all .2s;
+ -webkit-transition: all .2s
+}
+
+@-webkit-keyframes layui-rotate {
+ from {
+ -webkit-transform: rotate(0)
+ }
+ to {
+ -webkit-transform: rotate(360deg)
+ }
+}
+
+@keyframes layui-rotate {
+ from {
+ transform: rotate(0)
+ }
+ to {
+ transform: rotate(360deg)
+ }
+}
+
+.layui-anim-rotate {
+ -webkit-animation-name: layui-rotate;
+ animation-name: layui-rotate;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear
+}
+
+@-webkit-keyframes layui-up {
+ from {
+ -webkit-transform: translate3d(0, 100%, 0);
+ opacity: .3
+ }
+ to {
+ -webkit-transform: translate3d(0, 0, 0);
+ opacity: 1
+ }
+}
+
+@keyframes layui-up {
+ from {
+ transform: translate3d(0, 100%, 0);
+ opacity: .3
+ }
+ to {
+ transform: translate3d(0, 0, 0);
+ opacity: 1
+ }
+}
+
+.layui-anim-up {
+ -webkit-animation-name: layui-up;
+ animation-name: layui-up
+}
+
+@-webkit-keyframes layui-upbit {
+ from {
+ -webkit-transform: translate3d(0, 15px, 0);
+ opacity: .3
+ }
+ to {
+ -webkit-transform: translate3d(0, 0, 0);
+ opacity: 1
+ }
+}
+
+@keyframes layui-upbit {
+ from {
+ transform: translate3d(0, 15px, 0);
+ opacity: .3
+ }
+ to {
+ transform: translate3d(0, 0, 0);
+ opacity: 1
+ }
+}
+
+.layui-anim-upbit {
+ -webkit-animation-name: layui-upbit;
+ animation-name: layui-upbit
+}
+
+@keyframes layui-down {
+ 0% {
+ opacity: .3;
+ transform: translate3d(0, -100%, 0)
+ }
+ 100% {
+ opacity: 1;
+ transform: translate3d(0, 0, 0)
+ }
+}
+
+.layui-anim-down {
+ animation-name: layui-down
+}
+
+@keyframes layui-downbit {
+ 0% {
+ opacity: .3;
+ transform: translate3d(0, -5px, 0)
+ }
+ 100% {
+ opacity: 1;
+ transform: translate3d(0, 0, 0)
+ }
+}
+
+.layui-anim-downbit {
+ animation-name: layui-downbit
+}
+
+@-webkit-keyframes layui-scale {
+ 0% {
+ opacity: .3;
+ -webkit-transform: scale(.5)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale(1)
+ }
+}
+
+@keyframes layui-scale {
+ 0% {
+ opacity: .3;
+ -ms-transform: scale(.5);
+ transform: scale(.5)
+ }
+ 100% {
+ opacity: 1;
+ -ms-transform: scale(1);
+ transform: scale(1)
+ }
+}
+
+.layui-anim-scale {
+ -webkit-animation-name: layui-scale;
+ animation-name: layui-scale
+}
+
+@-webkit-keyframes layui-scale-spring {
+ 0% {
+ opacity: .5;
+ -webkit-transform: scale(.5)
+ }
+ 80% {
+ opacity: .8;
+ -webkit-transform: scale(1.1)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale(1)
+ }
+}
+
+@keyframes layui-scale-spring {
+ 0% {
+ opacity: .5;
+ transform: scale(.5)
+ }
+ 80% {
+ opacity: .8;
+ transform: scale(1.1)
+ }
+ 100% {
+ opacity: 1;
+ transform: scale(1)
+ }
+}
+
+.layui-anim-scaleSpring {
+ -webkit-animation-name: layui-scale-spring;
+ animation-name: layui-scale-spring
+}
+
+@keyframes layui-scalesmall {
+ 0% {
+ opacity: .3;
+ transform: scale(1.5)
+ }
+ 100% {
+ opacity: 1;
+ transform: scale(1)
+ }
+}
+
+.layui-anim-scalesmall {
+ animation-name: layui-scalesmall
+}
+
+@keyframes layui-scalesmall-spring {
+ 0% {
+ opacity: .3;
+ transform: scale(1.5)
+ }
+ 80% {
+ opacity: .8;
+ transform: scale(.9)
+ }
+ 100% {
+ opacity: 1;
+ transform: scale(1)
+ }
+}
+
+.layui-anim-scalesmall-spring {
+ animation-name: layui-scalesmall-spring
+}
+
+@-webkit-keyframes layui-fadein {
+ 0% {
+ opacity: 0
+ }
+ 100% {
+ opacity: 1
+ }
+}
+
+@keyframes layui-fadein {
+ 0% {
+ opacity: 0
+ }
+ 100% {
+ opacity: 1
+ }
+}
+
+.layui-anim-fadein {
+ -webkit-animation-name: layui-fadein;
+ animation-name: layui-fadein
+}
+
+@-webkit-keyframes layui-fadeout {
+ 0% {
+ opacity: 1
+ }
+ 100% {
+ opacity: 0
+ }
+}
+
+@keyframes layui-fadeout {
+ 0% {
+ opacity: 1
+ }
+ 100% {
+ opacity: 0
+ }
+}
+
+.layui-anim-fadeout {
+ -webkit-animation-name: layui-fadeout;
+ animation-name: layui-fadeout
+}
\ No newline at end of file
diff --git a/src/main/resources/static/lib/layui/css/modules/code.css b/src/main/resources/static/lib/layui/css/modules/code.css
new file mode 100644
index 0000000..0fee0c5
--- /dev/null
+++ b/src/main/resources/static/lib/layui/css/modules/code.css
@@ -0,0 +1 @@
+html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#FAFAFA;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view .layui-code-ol li:first-child{padding-top:10px}.layui-code-view .layui-code-ol li:last-child{padding-bottom:10px}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none}
\ No newline at end of file
diff --git a/src/main/resources/static/lib/layui/css/modules/laydate/default/laydate.css b/src/main/resources/static/lib/layui/css/modules/laydate/default/laydate.css
new file mode 100644
index 0000000..9f3064b
--- /dev/null
+++ b/src/main/resources/static/lib/layui/css/modules/laydate/default/laydate.css
@@ -0,0 +1 @@
+.laydate-set-ym,.layui-laydate,.layui-laydate *,.layui-laydate-list{box-sizing:border-box}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate{position:absolute;z-index:66666666;margin:5px 0;border-radius:2px;font-size:14px;-webkit-animation-duration:.2s;animation-duration:.2s;-webkit-animation-fill-mode:both;animation-fill-mode:both;animation-name:laydate-downbit}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}@keyframes laydate-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon,.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.laydate-set-ym span,.layui-laydate-header i{padding:0 5px;cursor:pointer}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;color:#999;font-size:18px}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:5px;text-align:center}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;height:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px 20px}.layui-laydate-footer span{margin-right:15px;display:inline-block;cursor:pointer;font-size:12px}.layui-laydate-footer span:hover{color:#5FB878}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{height:26px;line-height:26px;margin:0 0 0 -1px;padding:0 10px;border:1px solid #C9C9C9;background-color:#fff;white-space:nowrap;vertical-align:top;border-radius:2px}.layui-laydate-list>li,.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle}.layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;background-color:#fff}.layui-laydate-list>li{position:relative;width:33.3%;height:36px;line-height:36px;margin:3px 0;text-align:center;cursor:pointer}.laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.laydate-time-list p{position:relative;top:-4px;line-height:29px}.laydate-time-list ol{height:181px;overflow:hidden}.laydate-time-list>li:hover ol{overflow-y:auto}.laydate-time-list ol li{width:130%;padding-left:33px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px}.layui-laydate-range{width:546px}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid #e2e2e2}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#666}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#5FB878}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{font-weight:400;color:#333}.layui-laydate-content td{color:#666}.layui-laydate-content td.laydate-selected{background-color:#B5FFF8}.laydate-selected:hover{background-color:#00F7DE!important}.layui-laydate-content td:hover,.layui-laydate-list li:hover{background-color:#eee;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.laydate-selected.laydate-day-next,.laydate-selected.laydate-day-prev{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#FF5722}.laydate-day-mark::after{background-color:#5FB878}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#5FB878}.layui-laydate .layui-this{background-color:#009688!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#009688}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead,.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-selected,.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#009688!important}.laydate-theme-grid .laydate-selected.laydate-day-next,.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px}
\ No newline at end of file
diff --git a/src/main/resources/static/lib/layui/css/modules/layer/default/icon-ext.png b/src/main/resources/static/lib/layui/css/modules/layer/default/icon-ext.png
new file mode 100644
index 0000000..bbbb669
Binary files /dev/null and b/src/main/resources/static/lib/layui/css/modules/layer/default/icon-ext.png differ
diff --git a/src/main/resources/static/lib/layui/css/modules/layer/default/icon.png b/src/main/resources/static/lib/layui/css/modules/layer/default/icon.png
new file mode 100644
index 0000000..3e17da8
Binary files /dev/null and b/src/main/resources/static/lib/layui/css/modules/layer/default/icon.png differ
diff --git a/src/main/resources/static/lib/layui/css/modules/layer/default/layer.css b/src/main/resources/static/lib/layui/css/modules/layer/default/layer.css
new file mode 100644
index 0000000..ef1db1d
--- /dev/null
+++ b/src/main/resources/static/lib/layui/css/modules/layer/default/layer.css
@@ -0,0 +1 @@
+.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:50px;line-height:50px;border-bottom:1px solid #F0F0F0;font-size:14px;color:#333;overflow:hidden;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:17px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1E9FFF;background-color:#1E9FFF;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:300px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:260px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:300px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:51px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}}
\ No newline at end of file
diff --git a/src/main/resources/static/lib/layui/css/modules/layer/default/loading-0.gif b/src/main/resources/static/lib/layui/css/modules/layer/default/loading-0.gif
new file mode 100644
index 0000000..6f3c953
Binary files /dev/null and b/src/main/resources/static/lib/layui/css/modules/layer/default/loading-0.gif differ
diff --git a/src/main/resources/static/lib/layui/css/modules/layer/default/loading-1.gif b/src/main/resources/static/lib/layui/css/modules/layer/default/loading-1.gif
new file mode 100644
index 0000000..db3a483
Binary files /dev/null and b/src/main/resources/static/lib/layui/css/modules/layer/default/loading-1.gif differ
diff --git a/src/main/resources/static/lib/layui/css/modules/layer/default/loading-2.gif b/src/main/resources/static/lib/layui/css/modules/layer/default/loading-2.gif
new file mode 100644
index 0000000..5bb90fd
Binary files /dev/null and b/src/main/resources/static/lib/layui/css/modules/layer/default/loading-2.gif differ
diff --git a/src/main/resources/static/lib/layui/font/iconfont.eot b/src/main/resources/static/lib/layui/font/iconfont.eot
new file mode 100644
index 0000000..622d7ec
Binary files /dev/null and b/src/main/resources/static/lib/layui/font/iconfont.eot differ
diff --git a/src/main/resources/static/lib/layui/font/iconfont.svg b/src/main/resources/static/lib/layui/font/iconfont.svg
new file mode 100644
index 0000000..999ca1f
--- /dev/null
+++ b/src/main/resources/static/lib/layui/font/iconfont.svg
@@ -0,0 +1,554 @@
+
+
+
+
+
+Created by iconfont
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/static/lib/layui/font/iconfont.ttf b/src/main/resources/static/lib/layui/font/iconfont.ttf
new file mode 100644
index 0000000..06e30f9
Binary files /dev/null and b/src/main/resources/static/lib/layui/font/iconfont.ttf differ
diff --git a/src/main/resources/static/lib/layui/font/iconfont.woff b/src/main/resources/static/lib/layui/font/iconfont.woff
new file mode 100644
index 0000000..66a1783
Binary files /dev/null and b/src/main/resources/static/lib/layui/font/iconfont.woff differ
diff --git a/src/main/resources/static/lib/layui/font/iconfont.woff2 b/src/main/resources/static/lib/layui/font/iconfont.woff2
new file mode 100644
index 0000000..47e9980
Binary files /dev/null and b/src/main/resources/static/lib/layui/font/iconfont.woff2 differ
diff --git a/src/main/resources/static/lib/layui/layui.js b/src/main/resources/static/lib/layui/layui.js
new file mode 100644
index 0000000..c7e5181
--- /dev/null
+++ b/src/main/resources/static/lib/layui/layui.js
@@ -0,0 +1,5 @@
+/** layui v2.6.3 | Released under the MIT license */
+ ;!function(t){"use strict";var e=document,n={modules:{},status:{},timeout:10,event:{}},r=function(){this.v="2.6.3"},o=function(){var t=e.currentScript?e.currentScript.src:function(){for(var t,n=e.scripts,r=n.length-1,o=r;o>0;o--)if("interactive"===n[o].readyState){t=n[o].src;break}return t||n[r].src}();return t.substring(0,t.lastIndexOf("/")+1)}(),a=function(e,n){n=n||"log",t.console&&console[n]&&console[n]("layui error hint: "+e)},i="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),u=n.builtin={lay:"lay",layer:"layer",laydate:"laydate",laypage:"laypage",laytpl:"laytpl",layedit:"layedit",form:"form",upload:"upload",dropdown:"dropdown",transfer:"transfer",tree:"tree",table:"table",element:"element",rate:"rate",colorpicker:"colorpicker",slider:"slider",carousel:"carousel",flow:"flow",util:"util",code:"code",jquery:"jquery",all:"all","layui.all":"layui.all"};r.prototype.cache=n,r.prototype.define=function(t,e){var r=this,o="function"==typeof t,a=function(){var t=function(t,e){layui[t]=e,n.status[t]=!0};return"function"==typeof e&&e(function(r,o){t(r,o),n.callback[r]=function(){e(t)}}),this};return o&&(e=t,t=[]),r.use(t,a),r},r.prototype.use=function(t,r,l){function c(t,e){var r="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===t.type||r.test((t.currentTarget||t.srcElement).readyState))&&(n.modules[d]=e,y.removeChild(m),function o(){return++v>1e3*n.timeout/4?a(d+" is not a valid module","error"):void(n.status[d]?s():setTimeout(o,4))}())}function s(){l.push(layui[d]),t.length>1?p.use(t.slice(1),r,l):"function"==typeof r&&function(){return layui.jquery&&"function"==typeof layui.jquery?layui.jquery(function(){r.apply(layui,l)}):void r.apply(layui,l)}()}var p=this,f=n.dir=n.dir?n.dir:o,y=e.getElementsByTagName("head")[0];t=function(){return"string"==typeof t?[t]:"function"==typeof t?(r=t,["all"]):t}();var d=t[0],v=0;if(l=l||[],n.host=n.host||(f.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===t.length||layui["layui.all"]&&u[d])return s(),p;var h=(u[d]?f+"modules/":/^\{\/\}/.test(p.modules[d])?"":n.base||"")+(p.modules[d]||d)+".js";if(h=h.replace(/^\{\/\}/,""),!n.modules[d]&&layui[d]&&(n.modules[d]=h),n.modules[d])!function g(){return++v>1e3*n.timeout/4?a(d+" is not a valid module","error"):void("string"==typeof n.modules[d]&&n.status[d]?s():setTimeout(g,4))}();else{var m=e.createElement("script");m.async=!0,m.charset="utf-8",m.src=h+function(){var t=n.version===!0?n.v||(new Date).getTime():n.version||"";return t?"?v="+t:""}(),y.appendChild(m),!m.attachEvent||m.attachEvent.toString&&m.attachEvent.toString().indexOf("[native code")<0||i?m.addEventListener("load",function(t){c(t,h)},!1):m.attachEvent("onreadystatechange",function(t){c(t,h)}),n.modules[d]=h}return p},r.prototype.getStyle=function(e,n){var r=e.currentStyle?e.currentStyle:t.getComputedStyle(e,null);return r[r.getPropertyValue?"getPropertyValue":"getAttribute"](n)},r.prototype.link=function(t,r,o){var i=this,u=e.createElement("link"),l=e.getElementsByTagName("head")[0];"string"==typeof r&&(o=r);var c=(o||t).replace(/\.|\//g,""),s=u.id="layuicss-"+c,p=0;return u.rel="stylesheet",u.href=t+(n.debug?"?v="+(new Date).getTime():""),u.media="all",e.getElementById(s)||l.appendChild(u),"function"!=typeof r?i:(function f(){return++p>1e3*n.timeout/100?a(t+" timeout"):void(1989===parseInt(i.getStyle(e.getElementById(s),"width"))?function(){r()}():setTimeout(f,100))}(),i)},n.callback={},r.prototype.factory=function(t){if(layui[t])return"function"==typeof n.callback[t]?n.callback[t]:null},r.prototype.addcss=function(t,e,r){return layui.link(n.dir+"css/"+t,e,r)},r.prototype.img=function(t,e,n){var r=new Image;return r.src=t,r.complete?e(r):(r.onload=function(){r.onload=null,"function"==typeof e&&e(r)},void(r.onerror=function(t){r.onerror=null,"function"==typeof n&&n(t)}))},r.prototype.config=function(t){t=t||{};for(var e in t)n[e]=t[e];return this},r.prototype.modules=function(){var t={};for(var e in u)t[e]=u[e];return t}(),r.prototype.extend=function(t){var e=this;t=t||{};for(var n in t)e[n]||e.modules[n]?a(n+" Module already exists","error"):e.modules[n]=t[n];return e},r.prototype.router=function(t){var e=this,t=t||location.hash,n={path:[],search:{},hash:(t.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(t)?(t=t.replace(/^#\//,""),n.href="/"+t,t=t.replace(/([^#])(#.*$)/,"$1").split("/")||[],e.each(t,function(t,e){/^\w+=/.test(e)?function(){e=e.split("="),n.search[e[0]]=e[1]}():n.path.push(e)}),n):n},r.prototype.url=function(t){var e=this,n={pathname:function(){var e=t?function(){var e=(t.match(/\.[^.]+?\/.+/)||[])[0]||"";return e.replace(/^[^\/]+/,"").replace(/\?.+/,"")}():location.pathname;return e.replace(/^\//,"").split("/")}(),search:function(){var n={},r=(t?function(){var e=(t.match(/\?.+/)||[])[0]||"";return e.replace(/\#.+/,"")}():location.search).replace(/^\?+/,"").split("&");return e.each(r,function(t,e){var r=e.indexOf("="),o=function(){return r<0?e.substr(0,e.length):0!==r&&e.substr(0,r)}();o&&(n[o]=r>0?e.substr(r+1):null)}),n}(),hash:e.router(function(){return t?(t.match(/#.+/)||[])[0]||"":location.hash}())};return n},r.prototype.data=function(e,n,r){if(e=e||"layui",r=r||localStorage,t.JSON&&t.JSON.parse){if(null===n)return delete r[e];n="object"==typeof n?n:{key:n};try{var o=JSON.parse(r[e])}catch(a){var o={}}return"value"in n&&(o[n.key]=n.value),n.remove&&delete o[n.key],r[e]=JSON.stringify(o),n.key?o[n.key]:o}},r.prototype.sessionData=function(t,e){return this.data(t,e,sessionStorage)},r.prototype.device=function(e){var n=navigator.userAgent.toLowerCase(),r=function(t){var e=new RegExp(t+"/([^\\s\\_\\-]+)");return t=(n.match(e)||[])[1],t||!1},o={os:function(){return/windows/.test(n)?"windows":/linux/.test(n)?"linux":/iphone|ipod|ipad|ios/.test(n)?"ios":/mac/.test(n)?"mac":void 0}(),ie:function(){return!!(t.ActiveXObject||"ActiveXObject"in t)&&((n.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:r("micromessenger")};return e&&!o[e]&&(o[e]=r(e)),o.android=/android/.test(n),o.ios="ios"===o.os,o.mobile=!(!o.android&&!o.ios),o},r.prototype.hint=function(){return{error:a}},r.prototype.each=function(t,e){var n,r=this;if("function"!=typeof e)return r;if(t=t||[],t.constructor===Object){for(n in t)if(e.call(t[n],n,t[n]))break}else for(n=0;na?1:o0;o--)if("interactive"===n[o].readyState){t=n[o].src;break}return t||n[r].src}();return t.substring(0,t.lastIndexOf("/")+1)},n.stope=function(t){t=t||window.event,t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},n.each=function(t,e){var n,r=this;if("function"!=typeof e)return r;if(t=t||[],t.constructor===Object){for(n in t)if(e.call(t[n],n,t[n]))break}else for(n=0;n80?window.console&&console.error(u+".css: Invalid"):void(1989===parseInt(n.getStyle(e.getElementById(a),"width"))?r():setTimeout(l,100))}()},n.hasScrollbar=function(){return e.body.scrollHeight>(window.innerHeight||e.documentElement.clientHeight)},n.position=function(t,r,o){if(r){o=o||{},t!==e&&t!==n("body")[0]||(o.clickType="right");var i="right"===o.clickType?function(){var t=o.e||window.event||{};return{left:t.clientX,top:t.clientY,right:t.clientX,bottom:t.clientY}}():t.getBoundingClientRect(),c=r.offsetWidth,u=r.offsetHeight,a=function(t){return t=t?"scrollLeft":"scrollTop",e.body[t]|e.documentElement[t]},s=function(t){return e.documentElement[t?"clientWidth":"clientHeight"]},l=5,f=i.left,p=i.bottom;f+c+l>s("width")&&(f=s("width")-c-l),p+u+l>s()&&(i.top>u+l?p=i.top-u-2*l:"right"===o.clickType&&(p=s()-u-2*l,p<0&&(p=0)));var h=o.position;if(h&&(r.style.position=h),r.style.left=f+("fixed"===h?0:a(1))+"px",r.style.top=p+("fixed"===h?0:a())+"px",!n.hasScrollbar()){var d=r.getBoundingClientRect();!o.SYSTEM_RELOAD&&d.bottom+l>s()&&(o.SYSTEM_RELOAD=!0,setTimeout(function(){n.position(t,r,o)},50))}}},n.options=function(t,e){var r=n(t),o=e||"lay-options";try{return new Function("return "+(r.attr(o)||"{}"))()}catch(i){return hint.error("parseerror:"+i,"error"),{}}},n.isTopElem=function(t){var r=[e,n("body")[0]],o=!1;return n.each(r,function(e,n){if(n===t)return o=!0}),o},r.addStr=function(t,e){return t=t.replace(/\s+/," "),e=e.replace(/\s+/," ").split(" "),n.each(e,function(e,n){new RegExp("\\b"+n+"\\b").test(t)||(t=t+" "+n)}),t.replace(/^\s|\s$/,"")},r.removeStr=function(t,e){return t=t.replace(/\s+/," "),e=e.replace(/\s+/," ").split(" "),n.each(e,function(e,n){var r=new RegExp("\\b"+n+"\\b");r.test(t)&&(t=t.replace(r,""))}),t.replace(/\s+/," ").replace(/^\s|\s$/,"")},r.prototype.find=function(t){var e=this,r=0,o=[],i="object"==typeof t;return this.each(function(n,c){for(var u=i?[t]:c.querySelectorAll(t||null);r0)return r[0].style[t]}():r.each(function(r,i){"object"==typeof t?n.each(t,function(t,e){i.style[t]=o(e)}):i.style[t]=o(e)})},r.prototype.width=function(t){var e=this;return void 0===t?function(){if(e.length>0)return e[0].offsetWidth}():e.each(function(n,r){e.css("width",t)})},r.prototype.height=function(t){var e=this;return void 0===t?function(){if(e.length>0)return e[0].offsetHeight}():e.each(function(n,r){e.css("height",t)})},r.prototype.attr=function(t,e){var n=this;return void 0===e?function(){if(n.length>0)return n[0].getAttribute(t)}():n.each(function(n,r){r.setAttribute(t,e)})},r.prototype.removeAttr=function(t){return this.each(function(e,n){n.removeAttribute(t)})},r.prototype.html=function(t){return this.each(function(e,n){n.innerHTML=t})},r.prototype.val=function(t){return this.each(function(e,n){n.value=t})},r.prototype.append=function(t){return this.each(function(e,n){"object"==typeof t?n.appendChild(t):n.innerHTML=n.innerHTML+t})},r.prototype.remove=function(t){return this.each(function(e,n){t?n.removeChild(t):n.parentNode.removeChild(n)})},r.prototype.on=function(t,e){return this.each(function(n,r){r.attachEvent?r.attachEvent("on"+t,function(t){t.target=t.srcElement,e.call(r,t)}):r.addEventListener(t,e,!1)})},r.prototype.off=function(t,e){return this.each(function(n,r){r.detachEvent?r.detachEvent("on"+t,e):r.removeEventListener(t,e,!1)})},window.lay=n,window.layui&&layui.define&&layui.define(function(e){e(t,n)})}();layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},c={exp:function(e){return new RegExp(e,"g")},query:function(e,c,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return n((c||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var c="Laytpl Error: ";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$ueditor")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="ueditor.2.0",e("laytpl",o)});layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"上一页",a.next="next"in a?a.next:"下一页";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?''+a.prev+" ":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push(''+(a.first||1)+" ");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r2&&e.push('… ');r<=u;r++)r===a.curr?e.push('"+r+" "):e.push(''+r+" ");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1…'),0!==t&&e.push(''+(a.last||a.pages)+" ")),e.join("")}(),next:function(){return a.next?''+a.next+" ":""}(),count:'共 '+a.count+" 条 ",limit:function(){var e=[''];return layui.each(a.limits,function(t,n){e.push('"+n+" 条/页 ")}),e.join("")+" "}(),refresh:['',' '," "].join(""),skip:function(){return['到第',' ','页确定 '," "].join("")}()};return['',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"
"].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;oi.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)});!function(e){"use strict";var t=e.layui&&layui.define,a={getPath:e.lay&&lay.getPath?lay.getPath():"",link:function(t,a,l){n.path&&e.lay&&lay.link&&lay.link(n.path+t,a,l)}},n={v:"5.2.ueditor",config:{},index:e.laydate&&e.laydate.v?1e5:0,path:a.getPath,set:function(e){var t=this;return t.config=lay.extend({},t.config,e),t},ready:function(e){var l="laydate",i="",r=(t?"modules/laydate/":"theme/")+"default/laydate.css?v="+n.v+i;return t?layui.addcss(r,e,l):a.link(r,e,l),this}},l=function(){var e=this;return{hint:function(t){e.hint.call(e,t)},config:e.config}},i="laydate",r=".layui-laydate",o="layui-this",s="laydate-disabled",y=[100,2e5],d="layui-laydate-static",m="layui-laydate-list",c="laydate-selected",u="layui-laydate-hint",h="layui-laydate-footer",f=".laydate-btns-confirm",p="laydate-time-text",g=".laydate-btns-time",v=function(e){var t=this;t.index=++n.index,t.config=lay.extend({},t.config,n.config,e),n.ready(function(){t.init()})};v.isLeapYear=function(e){return e%4===0&&e%100!==0||e%400===0},v.prototype.config={type:"date",range:!1,format:"yyyy-MM-dd",value:null,isInitValue:!0,min:"1900-ueditor-ueditor",max:"2099-12-31",trigger:"click",show:!1,showBottom:!0,btns:["clear","now","confirm"],lang:"cn",theme:"default",position:null,calendar:!1,mark:{},zIndex:null,done:null,change:null},v.prototype.lang=function(){var e=this,t=e.config,a={cn:{weeks:["日","一","二","三","四","五","六"],time:["时","分","秒"],timeTips:"选择时间",startTime:"开始时间",endTime:"结束时间",dateTips:"返回日期",month:["一","二","三","四","五","六","七","八","九","十","十一","十二"],tools:{confirm:"确定",clear:"清空",now:"现在"},timeout:"结束时间不能早于开始时间 请重新选择",invalidDate:"不在有效日期或时间范围内",formatError:["日期格式不合法 必须遵循下述格式: "," 已为你重置"]},en:{weeks:["Su","Mo","Tu","We","Th","Fr","Sa"],time:["Hours","Minutes","Seconds"],timeTips:"Select Time",startTime:"Start Time",endTime:"End Time",dateTips:"Select Date",month:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],tools:{confirm:"Confirm",clear:"Clear",now:"Now"},timeout:"End time cannot be less than start Time Please re-select",invalidDate:"Invalid date",formatError:["The date format error Must be followed: "," It has been reset"]}};return a[t.lang]||a.cn},v.prototype.init=function(){var t=this,a=t.config,n="yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s",l="static"===a.position,i={year:"yyyy",month:"yyyy-MM",date:"yyyy-MM-dd",time:"HH:mm:ss",datetime:"yyyy-MM-dd HH:mm:ss"};a.elem=lay(a.elem),a.eventElem=lay(a.eventElem),a.elem[0]&&(a.range===!0&&(a.range="-"),i[a.type]||(e.console&&console.error&&console.error("laydate type error:'"+a.type+"' is not supported"),a.type="date"),a.format===i.date&&(a.format=i[a.type]||i.date),t.format=a.format.match(new RegExp(n+"|.","g"))||[],t.EXP_IF="",t.EXP_SPLIT="",lay.each(t.format,function(e,a){var l=new RegExp(n).test(a)?"\\d{"+function(){return new RegExp(n).test(t.format[0===e?e+1:e-1]||"")?/^yyyy|y$/.test(a)?4:a.length:/^yyyy$/.test(a)?"ueditor,4":/^y$/.test(a)?"ueditor,308":"ueditor,2"}()+"}":"\\"+a;t.EXP_IF=t.EXP_IF+l,t.EXP_SPLIT=t.EXP_SPLIT+"("+l+")"}),t.EXP_IF=new RegExp("^"+(a.range?t.EXP_IF+"\\s\\"+a.range+"\\s"+t.EXP_IF:t.EXP_IF)+"$"),t.EXP_SPLIT=new RegExp("^"+t.EXP_SPLIT+"$",""),t.isInput(a.elem[0])||"focus"===a.trigger&&(a.trigger="click"),a.elem.attr("lay-key")||(a.elem.attr("lay-key",t.index),a.eventElem.attr("lay-key",t.index)),a.mark=lay.extend({},a.calendar&&"cn"===a.lang?{"0-1-1":"元旦","0-2-14":"情人","0-3-8":"妇女","0-3-12":"植树","0-4-1":"愚人","0-5-1":"劳动","0-5-4":"青年","0-6-1":"儿童","0-9-10":"教师","0-9-18":"国耻","0-10-1":"国庆","0-12-25":"圣诞"}:{},a.mark),lay.each(["min","max"],function(e,t){var n=[],l=[];if("number"==typeof a[t]){var i=a[t],r=(new Date).getTime(),o=864e5,s=new Date(i?i0)return!0;var n=lay.elem("div",{"class":"layui-laydate-header"}),l=[function(){var e=lay.elem("i",{"class":"layui-icon laydate-icon laydate-prev-y"});return e.innerHTML="",e}(),function(){var e=lay.elem("i",{"class":"layui-icon laydate-icon laydate-prev-m"});return e.innerHTML="",e}(),function(){var e=lay.elem("div",{"class":"laydate-set-ym"}),t=lay.elem("span"),a=lay.elem("span");return e.appendChild(t),e.appendChild(a),e}(),function(){var e=lay.elem("i",{"class":"layui-icon laydate-icon laydate-next-m"});return e.innerHTML="",e}(),function(){var e=lay.elem("i",{"class":"layui-icon laydate-icon laydate-next-y"});return e.innerHTML="",e}()],y=lay.elem("div",{"class":"layui-laydate-content"}),d=lay.elem("table"),m=lay.elem("thead"),c=lay.elem("tr");lay.each(l,function(e,t){n.appendChild(t)}),m.appendChild(c),lay.each(new Array(6),function(e){var t=d.insertRow(0);lay.each(new Array(7),function(n){if(0===e){var l=lay.elem("th");l.innerHTML=a.weeks[n],c.appendChild(l)}t.insertCell(n)})}),d.insertBefore(m,d.children[0]),y.appendChild(d),i[e]=lay.elem("div",{"class":"layui-laydate-main laydate-main-list-"+e}),i[e].appendChild(n),i[e].appendChild(y),r.push(l),o.push(y),s.push(d)}),lay(y).html(function(){var e=[],l=[];return"datetime"===t.type&&e.push(''+a.timeTips+" "),lay.each(t.btns,function(e,i){var r=a.tools[i]||"btn";t.range&&"now"===i||(n&&"clear"===i&&(r="cn"===t.lang?"重置":"Reset"),l.push(''+r+" "))}),e.push('"),e.join("")}()),lay.each(i,function(e,t){l.appendChild(t)}),t.showBottom&&l.appendChild(y),/^#/.test(t.theme)){var m=lay.elem("style"),c=["#{{id}} .layui-laydate-header{background-color:{{theme}};}","#{{id}} .layui-this{background-color:{{theme}} !important;}"].join("").replace(/{{id}}/g,e.elemID).replace(/{{theme}}/g,t.theme);"styleSheet"in m?(m.setAttribute("type","text/css"),m.styleSheet.cssText=c):m.innerHTML=c,lay(l).addClass("laydate-theme-molv"),l.appendChild(m)}e.remove(v.thisElemDate),n?t.elem.append(l):(document.body.appendChild(l),e.position()),e.checkDate().calendar(null,0,"init"),e.changeEvent(),v.thisElemDate=e.elemID,"function"==typeof t.ready&&t.ready(lay.extend({},t.dateTime,{month:t.dateTime.month+1}))},v.prototype.remove=function(e){var t=this,a=(t.config,lay("#"+(e||t.elemID)));return a[0]?(a.hasClass(d)||t.checkDate(function(){a.remove(),delete t.endDate}),t):t},v.prototype.position=function(){var e=this,t=e.config;return lay.position(e.bindElem||t.elem[0],e.elem,{position:t.position}),e},v.prototype.hint=function(e){var t=this,a=(t.config,lay.elem("div",{"class":u}));t.elem&&(a.innerHTML=e||"",lay(t.elem).find("."+u).remove(),t.elem.appendChild(a),clearTimeout(t.hinTimer),t.hinTimer=setTimeout(function(){lay(t.elem).find("."+u).remove()},3e3))},v.prototype.getAsYM=function(e,t,a){return a?t--:t++,t<0&&(t=11,e--),t>11&&(t=0,e++),[e,t]},v.prototype.systemDate=function(e){var t=e||new Date;return{year:t.getFullYear(),month:t.getMonth(),date:t.getDate(),hours:e?e.getHours():0,minutes:e?e.getMinutes():0,seconds:e?e.getSeconds():0}},v.prototype.checkDate=function(e){var t,a,l=this,i=(new Date,l.config),r=l.lang(),o=i.dateTime=i.dateTime||l.systemDate(),s=l.bindElem||i.elem[0],d=(l.isInput(s)?"val":"html",l.isInput(s)?s.value:"static"===i.position?"":s.innerHTML),m=function(e){e.year>y[1]&&(e.year=y[1],a=!0),e.month>11&&(e.month=11,a=!0),e.hours>23&&(e.hours=0,a=!0),e.minutes>59&&(e.minutes=0,e.hours++,a=!0),e.seconds>59&&(e.seconds=0,e.minutes++,a=!0),t=n.getEndDate(e.month+1,e.year),e.date>t&&(e.date=t,a=!0)},c=function(e,t,n){var r=["startTime","endTime"];t=(t.match(l.EXP_SPLIT)||[]).slice(1),n=n||0,i.range&&(l[r[n]]=l[r[n]]||{}),lay.each(l.format,function(o,s){var d=parseFloat(t[o]);t[o].length'+a+""),n},v.prototype.limit=function(e,t,a,n){var l,i=this,r=i.config,o={},y=r[a>41?"endDate":"dateTime"],d=lay.extend({},y,t||{});return lay.each({now:d,min:r.min,max:r.max},function(e,t){o[e]=i.newDate(lay.extend({year:t.year,month:t.month,date:t.date},function(){var e={};return lay.each(n,function(a,n){e[n]=t[n]}),e}())).getTime()}),l=o.nowo.max,e&&e[l?"addClass":"removeClass"](s),l},v.prototype.thisDateTime=function(e){var t=this,a=t.config;return e?t.endDate:a.dateTime},v.prototype.calendar=function(e,t,a){var l,i,r,s=this,d=s.config,t=t?1:0,m=e||s.thisDateTime(t),c=new Date,u=s.lang(),h="date"!==d.type&&"datetime"!==d.type,p=lay(s.table[t]).find("td"),g=lay(s.elemHeader[t][2]).find("span");return m.yeary[1]&&(m.year=y[1],s.hint(u.invalidDate)),s.firstDate||(s.firstDate=lay.extend({},m)),c.setFullYear(m.year,m.month,1),l=c.getDay(),i=n.getEndDate(m.month||12,m.year),r=n.getEndDate(m.month+1,m.year),lay.each(p,function(e,t){var a=[m.year,m.month],n=0;t=lay(t),t.removeAttr("class"),e=l&&e=a.firstDate.year&&(i.month=n.max.month,i.date=n.max.date),a.limit(lay(l),i,t),C++}),lay(c[v?0:1]).attr("lay-ym",C-8+"-"+D[1]).html(w+T+" - "+(C-1+T))}else if("month"===e)lay.each(new Array(12),function(e){var l=lay.elem("li",{"lay-ym":e}),r={year:D[0],month:e};e+1==D[1]&&lay(l).addClass(o),l.innerHTML=i.month[e]+(v?"月":""),y.appendChild(l),D[0]=a.firstDate.year&&(r.date=n.max.date),a.limit(lay(l),r,t)}),lay(c[v?0:1]).attr("lay-ym",D[0]+"-"+D[1]).html(D[0]+T);else if("time"===e){var k=function(){lay(y).find("ol").each(function(e,n){lay(n).find("li").each(function(n,l){a.limit(lay(l),[{hours:n},{hours:a[x].hours,minutes:n},{hours:a[x].hours,minutes:a[x].minutes,seconds:n}][e],t,[["hours"],["hours","minutes"],["hours","minutes","seconds"]][e])})}),n.range||a.limit(lay(a.footer).find(f),a[x],0,["hours","minutes","seconds"])};n.range?a[x]||(a[x]={hours:0,minutes:0,seconds:0}):a[x]=l,lay.each([24,60,60],function(e,t){var n=lay.elem("li"),l=[""+i.time[e]+"
"];lay.each(new Array(t),function(t){l.push(""+lay.digit(t,2)+" ")}),n.innerHTML=l.join("")+" ",y.appendChild(n)}),k()}if(h&&u.removeChild(h),u.appendChild(y),"year"===e||"month"===e)lay(a.elemMain[t]).addClass("laydate-ym-show"),lay(y).find("li").on("click",function(){var i=0|lay(this).attr("lay-ym");if(!lay(this).hasClass(s)){0===t?(l[e]=i,a.limit(lay(a.footer).find(f),null,0)):a.endDate[e]=i;var d="year"===n.type||"month"===n.type;d?(lay(y).find("."+o).removeClass(o),lay(this).addClass(o),"month"===n.type&&"year"===e&&(a.listYM[t][0]=i,r&&(t?l.year=i:a.endDate.year=i),a.list("month",t))):(a.checkDate("limit").calendar(null,t),a.closeList()),a.setBtnStatus(),n.range||(("month"===n.type&&"month"===e||"year"===n.type&&"year"===e)&&a.setValue(a.parse()).remove().done(),a.done(null,"change")),lay(a.footer).find(g).removeClass(s)}});else{var E=lay.elem("span",{"class":p}),b=function(){lay(y).find("ol").each(function(e){var t=this,n=lay(t).find("li");t.scrollTop=30*(a[x][M[e]]-2),t.scrollTop<=0&&n.each(function(e,a){if(!lay(this).hasClass(s))return t.scrollTop=30*(e-2),!0})})},H=lay(d[2]).find("."+p);b(),E.innerHTML=n.range?[i.startTime,i.endTime][t]:i.timeTips,lay(a.elemMain[t]).addClass("laydate-time-show"),H[0]&&H.remove(),d[2].appendChild(E),lay(y).find("ol").each(function(e){var t=this;lay(t).find("li").on("click",function(){var i=0|this.innerHTML;lay(this).hasClass(s)||(n.range?a[x][M[e]]=i:l[M[e]]=i,lay(t).find("."+o).removeClass(o),lay(this).addClass(o),k(),b(),(a.endDate||"time"===n.type)&&a.done(null,"change"),a.setBtnStatus())})})}return a},v.prototype.listYM=[],v.prototype.closeList=function(){var e=this;e.config;lay.each(e.elemCont,function(t,a){lay(this).find("."+m).remove(),lay(e.elemMain[t]).removeClass("laydate-ym-show laydate-time-show")}),lay(e.elem).find("."+p).remove()},v.prototype.setBtnStatus=function(e,t,a){var n,l=this,i=l.config,r=l.lang(),o=lay(l.footer).find(f);i.range&&"time"!==i.type&&(t=t||i.dateTime,a=a||l.endDate,n=l.newDate(t).getTime()>l.newDate(a).getTime(),l.limit(null,t)||l.limit(null,a)?o.addClass(s):o[n?"addClass":"removeClass"](s),e&&n&&l.hint("string"==typeof e?r.timeout.replace(/日期/g,e):r.timeout))},v.prototype.parse=function(e,t){var a=this,n=a.config,l=t||(e?lay.extend({},a.endDate,a.endTime):n.range?lay.extend({},n.dateTime,a.startTime):n.dateTime),i=a.format.concat();return lay.each(i,function(e,t){/yyyy|y/.test(t)?i[e]=lay.digit(l.year,t.length):/MM|M/.test(t)?i[e]=lay.digit(l.month+1,t.length):/dd|d/.test(t)?i[e]=lay.digit(l.date,t.length):/HH|H/.test(t)?i[e]=lay.digit(l.hours,t.length):/mm|m/.test(t)?i[e]=lay.digit(l.minutes,t.length):/ss|s/.test(t)&&(i[e]=lay.digit(l.seconds,t.length))}),n.range&&!e?i.join("")+" "+n.range+" "+a.parse(1):i.join("")},v.prototype.newDate=function(e){return e=e||{},new Date(e.year||1,e.month||0,e.date||1,e.hours||0,e.minutes||0,e.seconds||0)},v.prototype.setValue=function(e){var t=this,a=t.config,n=t.bindElem||a.elem[0],l=t.isInput(n)?"val":"html";return"static"===a.position||lay(n)[l](e||""),this},v.prototype.stampRange=function(e,t){var a,n,l=this,i=l.config;i.range&&(a=l.newDate(i.dateTime).getTime(),n=l.newDate(l.endDate).getTime(),lay.each(t,function(t,i){var r=lay(i).attr("lay-ymd").split("-"),o=l.newDate({year:r[0],month:r[1]-1,date:r[2]}).getTime();0==e?o>a&&lay(i).addClass(c):o0&&t-1 in e)}function r(e,t,n){if(pe.isFunction(t))return pe.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return pe.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(Ce.test(t))return pe.filter(t,e,n);t=pe.filter(t,e)}return pe.grep(e,function(e){return pe.inArray(e,t)>-1!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t={};return pe.each(e.match(De)||[],function(e,n){t[n]=!0}),t}function a(){re.addEventListener?(re.removeEventListener("DOMContentLoaded",s),e.removeEventListener("load",s)):(re.detachEvent("onreadystatechange",s),e.detachEvent("onload",s))}function s(){(re.addEventListener||"load"===e.event.type||"complete"===re.readyState)&&(a(),pe.ready())}function u(e,t,n){if(void 0===n&&1===e.nodeType){var r="data-"+t.replace(_e,"-$ueditor").toLowerCase();if(n=e.getAttribute(r),"string"==typeof n){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:qe.test(n)?pe.parseJSON(n):n)}catch(i){}pe.data(e,t,n)}else n=void 0}return n}function l(e){var t;for(t in e)if(("data"!==t||!pe.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function c(e,t,n,r){if(He(e)){var i,o,a=pe.expando,s=e.nodeType,u=s?pe.cache:e,l=s?e[a]:e[a]&&a;if(l&&u[l]&&(r||u[l].data)||void 0!==n||"string"!=typeof t)return l||(l=s?e[a]=ne.pop()||pe.guid++:a),u[l]||(u[l]=s?{}:{toJSON:pe.noop}),"object"!=typeof t&&"function"!=typeof t||(r?u[l]=pe.extend(u[l],t):u[l].data=pe.extend(u[l].data,t)),o=u[l],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[pe.camelCase(t)]=n),"string"==typeof t?(i=o[t],null==i&&(i=o[pe.camelCase(t)])):i=o,i}}function f(e,t,n){if(He(e)){var r,i,o=e.nodeType,a=o?pe.cache:e,s=o?e[pe.expando]:pe.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){pe.isArray(t)?t=t.concat(pe.map(t,pe.camelCase)):t in r?t=[t]:(t=pe.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;for(;i--;)delete r[t[i]];if(n?!l(r):!pe.isEmptyObject(r))return}(n||(delete a[s].data,l(a[s])))&&(o?pe.cleanData([e],!0):fe.deleteExpando||a!=a.window?delete a[s]:a[s]=void 0)}}}function d(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return pe.css(e,t,"")},u=s(),l=n&&n[3]||(pe.cssNumber[t]?"":"px"),c=(pe.cssNumber[t]||"px"!==l&&+u)&&Me.exec(pe.css(e,t));if(c&&c[3]!==l){l=l||c[3],n=n||[],c=+u||1;do o=o||".5",c/=o,pe.style(e,t,c+l);while(o!==(o=s()/u)&&1!==o&&--a)}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}function p(e){var t=ze.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function h(e,t){var n,r,i=0,o="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||pe.nodeName(r,t)?o.push(r):pe.merge(o,h(r,t));return void 0===t||t&&pe.nodeName(e,t)?pe.merge([e],o):o}function g(e,t){for(var n,r=0;null!=(n=e[r]);r++)pe._data(n,"globalEval",!t||pe._data(t[r],"globalEval"))}function m(e){Be.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t,n,r,i){for(var o,a,s,u,l,c,f,d=e.length,y=p(t),v=[],x=0;x"!==f[1]||Ve.test(a)?0:u:u.firstChild,o=a&&a.childNodes.length;o--;)pe.nodeName(c=a.childNodes[o],"tbody")&&!c.childNodes.length&&a.removeChild(c);for(pe.merge(v,u.childNodes),u.textContent="";u.firstChild;)u.removeChild(u.firstChild);u=y.lastChild}else v.push(t.createTextNode(a));for(u&&y.removeChild(u),fe.appendChecked||pe.grep(h(v,"input"),m),x=0;a=v[x++];)if(r&&pe.inArray(a,r)>-1)i&&i.push(a);else if(s=pe.contains(a.ownerDocument,a),u=h(y.appendChild(a),"script"),s&&g(u),n)for(o=0;a=u[o++];)Ie.test(a.type||"")&&n.push(a);return u=null,y}function v(){return!0}function x(){return!1}function b(){try{return re.activeElement}catch(e){}}function w(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)w(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),i===!1)i=x;else if(!i)return e;return 1===o&&(a=i,i=function(e){return pe().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=pe.guid++)),e.each(function(){pe.event.add(this,t,i,r,n)})}function T(e,t){return pe.nodeName(e,"table")&&pe.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function C(e){return e.type=(null!==pe.find.attr(e,"type"))+"/"+e.type,e}function E(e){var t=it.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function N(e,t){if(1===t.nodeType&&pe.hasData(e)){var n,r,i,o=pe._data(e),a=pe._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;r1&&"string"==typeof p&&!fe.checkClone&&rt.test(p))return e.each(function(i){var o=e.eq(i);g&&(t[0]=p.call(this,i,o.html())),S(o,t,n,r)});if(f&&(l=y(t,e[0].ownerDocument,!1,e,r),i=l.firstChild,1===l.childNodes.length&&(l=i),i||r)){for(s=pe.map(h(l,"script"),C),a=s.length;c ")).appendTo(t.documentElement),t=(ut[0].contentWindow||ut[0].contentDocument).document,t.write(),t.close(),n=D(e,t),ut.detach()),lt[e]=n),n}function L(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function H(e){if(e in Et)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=Ct.length;n--;)if(e=Ct[n]+t,e in Et)return e}function q(e,t){for(var n,r,i,o=[],a=0,s=e.length;a=0&&n=0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},isPlainObject:function(e){var t;if(!e||"object"!==pe.type(e)||e.nodeType||pe.isWindow(e))return!1;try{if(e.constructor&&!ce.call(e,"constructor")&&!ce.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}if(!fe.ownFirst)for(t in e)return ce.call(e,t);for(t in e);return void 0===t||ce.call(e,t)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?ue[le.call(e)]||"object":typeof e},globalEval:function(t){t&&pe.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(ge,"ms-").replace(me,ye)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var r,i=0;if(n(e))for(r=e.length;iT.cacheLength&&delete e[t.shift()],e[n+" "]=r}var t=[];return e}function r(e){return e[P]=!0,e}function i(e){var t=H.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split("|"),r=n.length;r--;)T.attrHandle[n[r]]=t}function a(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function f(){}function d(e){for(var t=0,n=e.length,r="";t1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,n,r){for(var i=0,o=n.length;i-1&&(r[l]=!(a[l]=f))}}else x=m(x===a?x.splice(h,x.length):x),o?o(null,a,x,u):Q.apply(a,x)})}function v(e){for(var t,n,r,i=e.length,o=T.relative[e[0].type],a=o||T.relative[" "],s=o?1:0,u=p(function(e){return e===t},a,!0),l=p(function(e){return ee(t,e)>-1},a,!0),c=[function(e,n,r){var i=!o&&(r||n!==A)||((t=n).nodeType?u(e,n,r):l(e,n,r));return t=null,i}];s1&&h(c),s>1&&d(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(se,"$1"),n,s0,o=e.length>0,a=function(r,a,s,u,l){var c,f,d,p=0,h="0",g=r&&[],y=[],v=A,x=r||o&&T.find.TAG("*",l),b=W+=null==v?1:Math.random()||.1,w=x.length;for(l&&(A=a===H||a||l);h!==w&&null!=(c=x[h]);h++){if(o&&c){for(f=0,a||c.ownerDocument===H||(L(c),s=!_);d=e[f++];)if(d(c,a||H,s)){u.push(c);break}l&&(W=b)}i&&((c=!d&&c)&&p--,r&&g.push(c))}if(p+=h,i&&h!==p){for(f=0;d=n[f++];)d(g,y,a,s);if(r){if(p>0)for(;h--;)g[h]||y[h]||(y[h]=G.call(u));y=m(y)}Q.apply(u,y),l&&!r&&y.length>0&&p+n.length>1&&t.uniqueSort(u)}return l&&(W=b,A=v),g};return i?r(a):a}var b,w,T,C,E,N,k,S,A,D,j,L,H,q,_,F,M,O,R,P="sizzle"+1*new Date,B=e.document,W=0,I=0,$=n(),z=n(),X=n(),U=function(e,t){return e===t&&(j=!0),0},V=1<<31,Y={}.hasOwnProperty,J=[],G=J.pop,K=J.push,Q=J.push,Z=J.slice,ee=function(e,t){for(var n=0,r=e.length;n+~]|"+ne+")"+ne+"*"),ce=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),fe=new RegExp(oe),de=new RegExp("^"+re+"$"),pe={ID:new RegExp("^#("+re+")"),CLASS:new RegExp("^\\.("+re+")"),TAG:new RegExp("^("+re+"|[*])"),ATTR:new RegExp("^"+ie),PSEUDO:new RegExp("^"+oe),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},he=/^(?:input|select|textarea|button)$/i,ge=/^h\d$/i,me=/^[^{]+\{\s*\[native \w/,ye=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ve=/[+~]/,xe=/'|\\/g,be=new RegExp("\\\\([\\da-f]{ueditor,6}"+ne+"?|("+ne+")|.)","ig"),we=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},Te=function(){L()};try{Q.apply(J=Z.call(B.childNodes),B.childNodes),J[B.childNodes.length].nodeType}catch(Ce){Q={apply:J.length?function(e,t){K.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}w=t.support={},E=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},L=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:B;return r!==H&&9===r.nodeType&&r.documentElement?(H=r,q=H.documentElement,_=!E(H),(n=H.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",Te,!1):n.attachEvent&&n.attachEvent("onunload",Te)),w.attributes=i(function(e){return e.className="i",!e.getAttribute("className")}),w.getElementsByTagName=i(function(e){return e.appendChild(H.createComment("")),!e.getElementsByTagName("*").length}),w.getElementsByClassName=me.test(H.getElementsByClassName),w.getById=i(function(e){return q.appendChild(e).id=P,!H.getElementsByName||!H.getElementsByName(P).length}),w.getById?(T.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&_){var n=t.getElementById(e);return n?[n]:[]}},T.filter.ID=function(e){var t=e.replace(be,we);return function(e){return e.getAttribute("id")===t}}):(delete T.find.ID,T.filter.ID=function(e){var t=e.replace(be,we);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}}),T.find.TAG=w.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):w.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},T.find.CLASS=w.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&_)return t.getElementsByClassName(e)},M=[],F=[],(w.qsa=me.test(H.querySelectorAll))&&(i(function(e){q.appendChild(e).innerHTML=" ",e.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||F.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+P+"-]").length||F.push("~="),e.querySelectorAll(":checked").length||F.push(":checked"),e.querySelectorAll("a#"+P+"+*").length||F.push(".#.+[+~]")}),i(function(e){var t=H.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&F.push("name"+ne+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||F.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),F.push(",.*:")})),(w.matchesSelector=me.test(O=q.matches||q.webkitMatchesSelector||q.mozMatchesSelector||q.oMatchesSelector||q.msMatchesSelector))&&i(function(e){w.disconnectedMatch=O.call(e,"div"),O.call(e,"[s!='']:x"),M.push("!=",oe)}),F=F.length&&new RegExp(F.join("|")),M=M.length&&new RegExp(M.join("|")),t=me.test(q.compareDocumentPosition),R=t||me.test(q.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return j=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!w.sortDetached&&t.compareDocumentPosition(e)===n?e===H||e.ownerDocument===B&&R(B,e)?-1:t===H||t.ownerDocument===B&&R(B,t)?1:D?ee(D,e)-ee(D,t):0:4&n?-1:1)}:function(e,t){if(e===t)return j=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],u=[t];if(!i||!o)return e===H?-1:t===H?1:i?-1:o?1:D?ee(D,e)-ee(D,t):0;if(i===o)return a(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;s[r]===u[r];)r++;return r?a(s[r],u[r]):s[r]===B?-1:u[r]===B?1:0},H):H},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==H&&L(e),n=n.replace(ce,"='$ueditor']"),w.matchesSelector&&_&&!X[n+" "]&&(!M||!M.test(n))&&(!F||!F.test(n)))try{var r=O.call(e,n);if(r||w.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return t(n,H,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==H&&L(e),R(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==H&&L(e);var n=T.attrHandle[t.toLowerCase()],r=n&&Y.call(T.attrHandle,t.toLowerCase())?n(e,t,!_):void 0;return void 0!==r?r:w.attributes||!_?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(j=!w.detectDuplicates,D=!w.sortStable&&e.slice(0),e.sort(U),j){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return D=null,e},C=t.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=C(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=C(t);return n},T=t.selectors={cacheLength:50,createPseudo:r,match:pe,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(be,we),e[3]=(e[3]||e[4]||e[5]||"").replace(be,we),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&fe.test(n)&&(t=N(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(be,we).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=$[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&$(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?"!="===n:!n||(o+="","="===n?o===r:"!="===n?o!==r:"^="===n?r&&0===o.indexOf(r):"*="===n?r&&o.indexOf(r)>-1:"$="===n?r&&o.slice(-r.length)===r:"~="===n?(" "+o.replace(ae," ")+" ").indexOf(r)>-1:"|="===n&&(o===r||o.slice(0,r.length+1)===r+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,d,p,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s,x=!1;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(s?d.nodeName.toLowerCase()===y:1===d.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(d=m,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p&&l[2],
+d=p&&m.childNodes[p];d=++p&&d&&d[g]||(x=p=0)||h.pop();)if(1===d.nodeType&&++x&&d===t){c[e]=[W,p,x];break}}else if(v&&(d=t,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p),x===!1)for(;(d=++p&&d&&d[g]||(x=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==y:1!==d.nodeType)||!++x||(v&&(f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),c[e]=[W,x]),d!==t)););return x-=i,x===r||x%r===0&&x/r>=0}}},PSEUDO:function(e,n){var i,o=T.pseudos[e]||T.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return o[P]?o(n):o.length>1?(i=[e,e,"",n],T.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),a=i.length;a--;)r=ee(e,i[a]),e[r]=!(t[r]=i[a])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=k(e.replace(se,"$1"));return i[P]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(be,we),function(t){return(t.textContent||t.innerText||C(t)).indexOf(e)>-1}}),lang:r(function(e){return de.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(be,we).toLowerCase(),function(t){var n;do if(n=_?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===q},focus:function(e){return e===H.activeElement&&(!H.hasFocus||H.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!T.pseudos.empty(e)},header:function(e){return ge.test(e.nodeName)},input:function(e){return he.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r2&&"ID"===(a=o[0]).type&&w.getById&&9===t.nodeType&&_&&T.relative[o[1].type]){if(t=(T.find.ID(a.matches[0].replace(be,we),t)||[])[0],!t)return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=pe.needsContext.test(e)?0:o.length;i--&&(a=o[i],!T.relative[s=a.type]);)if((u=T.find[s])&&(r=u(a.matches[0].replace(be,we),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),e=r.length&&d(o),!e)return Q.apply(n,r),n;break}}return(l||k(e,f))(r,t,!_,n,!t||ve.test(e)&&c(t.parentNode)||t),n},w.sortStable=P.split("").sort(U).join("")===P,w.detectDuplicates=!!j,L(),w.sortDetached=i(function(e){return 1&e.compareDocumentPosition(H.createElement("div"))}),i(function(e){return e.innerHTML=" ","#"===e.firstChild.getAttribute("href")})||o("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),w.attributes&&i(function(e){return e.innerHTML=" ",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||o("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute("disabled")})||o(te,function(e,t,n){var r;if(!n)return e[t]===!0?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);pe.find=ve,pe.expr=ve.selectors,pe.expr[":"]=pe.expr.pseudos,pe.uniqueSort=pe.unique=ve.uniqueSort,pe.text=ve.getText,pe.isXMLDoc=ve.isXML,pe.contains=ve.contains;var xe=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&pe(e).is(n))break;r.push(e)}return r},be=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},we=pe.expr.match.needsContext,Te=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,Ce=/^.[^:#\[\.,]*$/;pe.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?pe.find.matchesSelector(r,e)?[r]:[]:pe.find.matches(e,pe.grep(t,function(e){return 1===e.nodeType}))},pe.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(pe(e).filter(function(){for(t=0;t1?pe.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},filter:function(e){return this.pushStack(r(this,e||[],!1))},not:function(e){return this.pushStack(r(this,e||[],!0))},is:function(e){return!!r(this,"string"==typeof e&&we.test(e)?pe(e):e||[],!1).length}});var Ee,Ne=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,ke=pe.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||Ee,"string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:Ne.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof pe?t[0]:t,pe.merge(this,pe.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:re,!0)),Te.test(r[1])&&pe.isPlainObject(t))for(r in t)pe.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if(i=re.getElementById(r[2]),i&&i.parentNode){if(i.id!==r[2])return Ee.find(e);this.length=1,this[0]=i}return this.context=re,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):pe.isFunction(e)?"undefined"!=typeof n.ready?n.ready(e):e(pe):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),pe.makeArray(e,this))};ke.prototype=pe.fn,Ee=pe(re);var Se=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};pe.fn.extend({has:function(e){var t,n=pe(e,this),r=n.length;return this.filter(function(){for(t=0;t-1:1===n.nodeType&&pe.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?pe.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?pe.inArray(this[0],pe(e)):pe.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(pe.uniqueSort(pe.merge(this.get(),pe(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),pe.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return xe(e,"parentNode")},parentsUntil:function(e,t,n){return xe(e,"parentNode",n)},next:function(e){return i(e,"nextSibling")},prev:function(e){return i(e,"previousSibling")},nextAll:function(e){return xe(e,"nextSibling")},prevAll:function(e){return xe(e,"previousSibling")},nextUntil:function(e,t,n){return xe(e,"nextSibling",n)},prevUntil:function(e,t,n){return xe(e,"previousSibling",n)},siblings:function(e){return be((e.parentNode||{}).firstChild,e)},children:function(e){return be(e.firstChild)},contents:function(e){return pe.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:pe.merge([],e.childNodes)}},function(e,t){pe.fn[e]=function(n,r){var i=pe.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=pe.filter(r,i)),this.length>1&&(Ae[e]||(i=pe.uniqueSort(i)),Se.test(e)&&(i=i.reverse())),this.pushStack(i)}});var De=/\S+/g;pe.Callbacks=function(e){e="string"==typeof e?o(e):pe.extend({},e);var t,n,r,i,a=[],s=[],u=-1,l=function(){for(i=e.once,r=t=!0;s.length;u=-1)for(n=s.shift();++u-1;)a.splice(n,1),n<=u&&u--}),this},has:function(e){return e?pe.inArray(e,a)>-1:a.length>0},empty:function(){return a&&(a=[]),this},disable:function(){return i=s=[],a=n="",this},disabled:function(){return!a},lock:function(){return i=!0,n||c.disable(),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||l()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},pe.extend({Deferred:function(e){var t=[["resolve","done",pe.Callbacks("once memory"),"resolved"],["reject","fail",pe.Callbacks("once memory"),"rejected"],["notify","progress",pe.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return pe.Deferred(function(n){pe.each(t,function(t,o){var a=pe.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&pe.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[o[0]+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?pe.extend(e,r):r}},i={};return r.pipe=r.then,pe.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=ie.call(arguments),a=o.length,s=1!==a||e&&pe.isFunction(e.promise)?a:0,u=1===s?e:pe.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?ie.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=new Array(a),n=new Array(a),r=new Array(a);i0||(je.resolveWith(re,[pe]),pe.fn.triggerHandler&&(pe(re).triggerHandler("ready"),pe(re).off("ready"))))}}),pe.ready.promise=function(t){if(!je)if(je=pe.Deferred(),"complete"===re.readyState||"loading"!==re.readyState&&!re.documentElement.doScroll)e.setTimeout(pe.ready);else if(re.addEventListener)re.addEventListener("DOMContentLoaded",s),e.addEventListener("load",s);else{re.attachEvent("onreadystatechange",s),e.attachEvent("onload",s);var n=!1;try{n=null==e.frameElement&&re.documentElement}catch(r){}n&&n.doScroll&&!function i(){if(!pe.isReady){try{n.doScroll("left")}catch(t){return e.setTimeout(i,50)}a(),pe.ready()}}()}return je.promise(t)},pe.ready.promise();var Le;for(Le in pe(fe))break;fe.ownFirst="0"===Le,fe.inlineBlockNeedsLayout=!1,pe(function(){var e,t,n,r;n=re.getElementsByTagName("body")[0],n&&n.style&&(t=re.createElement("div"),r=re.createElement("div"),r.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",n.appendChild(r).appendChild(t),"undefined"!=typeof t.style.zoom&&(t.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:ueditor",fe.inlineBlockNeedsLayout=e=3===t.offsetWidth,e&&(n.style.zoom=1)),n.removeChild(r))}),function(){var e=re.createElement("div");fe.deleteExpando=!0;try{delete e.test}catch(t){fe.deleteExpando=!1}e=null}();var He=function(e){var t=pe.noData[(e.nodeName+" ").toLowerCase()],n=+e.nodeType||1;return(1===n||9===n)&&(!t||t!==!0&&e.getAttribute("classid")===t)},qe=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,_e=/([A-Z])/g;pe.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?pe.cache[e[pe.expando]]:e[pe.expando],!!e&&!l(e)},data:function(e,t,n){return c(e,t,n)},removeData:function(e,t){return f(e,t)},_data:function(e,t,n){return c(e,t,n,!0)},_removeData:function(e,t){return f(e,t,!0)}}),pe.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=pe.data(o),1===o.nodeType&&!pe._data(o,"parsedAttrs"))){for(n=a.length;n--;)a[n]&&(r=a[n].name,0===r.indexOf("data-")&&(r=pe.camelCase(r.slice(5)),u(o,r,i[r])));pe._data(o,"parsedAttrs",!0)}return i}return"object"==typeof e?this.each(function(){pe.data(this,e)}):arguments.length>1?this.each(function(){pe.data(this,e,t)}):o?u(o,e,pe.data(o,e)):void 0},removeData:function(e){return this.each(function(){pe.removeData(this,e)})}}),pe.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=pe._data(e,t),n&&(!r||pe.isArray(n)?r=pe._data(e,t,pe.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=pe.queue(e,t),r=n.length,i=n.shift(),o=pe._queueHooks(e,t),a=function(){pe.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return pe._data(e,n)||pe._data(e,n,{empty:pe.Callbacks("once memory").add(function(){pe._removeData(e,t+"queue"),pe._removeData(e,n)})})}}),pe.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length a ",fe.leadingWhitespace=3===e.firstChild.nodeType,fe.tbody=!e.getElementsByTagName("tbody").length,fe.htmlSerialize=!!e.getElementsByTagName("link").length,fe.html5Clone="<:nav>"!==re.createElement("nav").cloneNode(!0).outerHTML,n.type="checkbox",n.checked=!0,t.appendChild(n),fe.appendChecked=n.checked,e.innerHTML="",fe.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue,t.appendChild(e),n=re.createElement("input"),n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),e.appendChild(n),fe.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,fe.noCloneEvent=!!e.addEventListener,e[pe.expando]=1,fe.attributes=!e.getAttribute(pe.expando)}();var Xe={option:[1,""," "],legend:[1,""," "],area:[1,""," "],param:[1,""," "],thead:[1,""],tr:[2,""],col:[2,""],td:[3,""],_default:fe.htmlSerialize?[0,"",""]:[1,"X","
"]};Xe.optgroup=Xe.option,Xe.tbody=Xe.tfoot=Xe.colgroup=Xe.caption=Xe.thead,Xe.th=Xe.td;var Ue=/<|?\w+;/,Ve=/-1&&(h=p.split("."),p=h.shift(),h.sort()),a=p.indexOf(":")<0&&"on"+p,t=t[pe.expando]?t:new pe.Event(p,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=h.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:pe.makeArray(n,[t]),l=pe.event.special[p]||{},i||!l.trigger||l.trigger.apply(r,n)!==!1)){if(!i&&!l.noBubble&&!pe.isWindow(r)){for(u=l.delegateType||p,Ke.test(u+p)||(s=s.parentNode);s;s=s.parentNode)d.push(s),c=s;c===(r.ownerDocument||re)&&d.push(c.defaultView||c.parentWindow||e)}for(f=0;(s=d[f++])&&!t.isPropagationStopped();)t.type=f>1?u:l.bindType||p,o=(pe._data(s,"events")||{})[t.type]&&pe._data(s,"handle"),o&&o.apply(s,n),o=a&&s[a],o&&o.apply&&He(s)&&(t.result=o.apply(s,n),t.result===!1&&t.preventDefault());if(t.type=p,!i&&!t.isDefaultPrevented()&&(!l._default||l._default.apply(d.pop(),n)===!1)&&He(r)&&a&&r[p]&&!pe.isWindow(r)){c=r[a],c&&(r[a]=null),pe.event.triggered=p;try{r[p]()}catch(g){}pe.event.triggered=void 0,c&&(r[a]=c)}return t.result}},dispatch:function(e){e=pe.event.fix(e);var t,n,r,i,o,a=[],s=ie.call(arguments),u=(pe._data(this,"events")||{})[e.type]||[],l=pe.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){for(a=pe.event.handlers.call(this,e,u),t=0;(i=a[t++])&&!e.isPropagationStopped();)for(e.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(o.namespace)||(e.handleObj=o,e.data=o.data,r=((pe.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s),void 0!==r&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,a=[],s=t.delegateCount,u=e.target;if(s&&u.nodeType&&("click"!==e.type||isNaN(e.button)||e.button<1))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(r=[],n=0;n-1:pe.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&a.push({elem:u,handlers:r})}return s ]","i"),tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,nt=/
-
+
-
\ No newline at end of file
+