Commit d9b4a048 authored by AfirSraftGarrier's avatar AfirSraftGarrier

Merge branch 'for-yx'

# Conflicts:
#	license/pom.xml
#	license/src/main/java/iot/sixiang/license/controller/SysOperLogController.java
#	license/src/main/java/iot/sixiang/license/controller/UserController.java
#	license/src/main/java/iot/sixiang/license/handler/GlobalExceptionHandler.java
#	license/src/main/java/iot/sixiang/license/mapper/SysOperLogMapper.java
#	license/src/main/java/iot/sixiang/license/net/TcpClient.java
#	license/src/main/java/iot/sixiang/license/service/SysOperLogService.java
#	license/src/main/java/iot/sixiang/license/service/UserService.java
#	license/src/main/java/iot/sixiang/license/service/impl/SysOperLogServiceImpl.java
#	license/src/main/java/iot/sixiang/license/service/impl/UserServiceImpl.java
#	license/src/main/java/iot/sixiang/license/util/CommonUtil.java
#	license/src/main/resources/mapper/PmsUseLogMapper.xml
#	license/src/main/resources/mapper/SysOperLogMapper.xml
parents 0e466f24 cdff0268
...@@ -33,3 +33,5 @@ build/ ...@@ -33,3 +33,5 @@ build/
.vscode/ .vscode/
*-acc.yml *-acc.yml
logs
\ No newline at end of file
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
<description>Demo project for Spring Boot</description> <description>Demo project for Spring Boot</description>
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<acc.log.version>1.0.2</acc.log.version>
</properties> </properties>
<dependencies> <dependencies>
...@@ -82,7 +81,7 @@ ...@@ -82,7 +81,7 @@
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson</artifactId>
<version>2.0.4</version> <version>2.0.9</version>
</dependency> </dependency>
<dependency> <dependency>
...@@ -102,31 +101,83 @@ ...@@ -102,31 +101,83 @@
<artifactId>spring-boot-starter-aop</artifactId> <artifactId>spring-boot-starter-aop</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.acc</groupId> <groupId>com.github.ulisesbocchio</groupId>
<artifactId>log</artifactId> <artifactId>jasypt-spring-boot-starter</artifactId>
<version>${acc.log.version}</version> <version>3.0.3</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.7.22</version> <version>5.7.22</version>
</dependency> </dependency>
</dependencies> <dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.69</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.owasp.antisamy</groupId>
<artifactId>antisamy</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>
<!--邮件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.sixiang.iot</groupId>
<artifactId>server-license</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/Safety.jar</systemPath>
</dependency>
<dependency>
<groupId>com.acc</groupId>
<artifactId>secret</artifactId>
<version>1.0.5</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/secret-1.0.5.jar</systemPath>
</dependency>
<repositories> </dependencies>
<repository>
<id>maven-releases</id>
<url>http://120.24.220.98:8868/repository/maven-public/</url>
</repository>
</repositories>
<build> <build>
<finalName>license</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 打包时包含引入的外部jar包 -->
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
......
...@@ -4,17 +4,16 @@ import org.mybatis.spring.annotation.MapperScan; ...@@ -4,17 +4,16 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@EnableAsync
@ServletComponentScan(basePackages = "iot.sixiang.license") @ServletComponentScan(basePackages = "iot.sixiang.license")
@SpringBootApplication @SpringBootApplication
@EnableScheduling @EnableScheduling
@MapperScan(basePackages = "iot.sixiang.license.mapper") @MapperScan(basePackages = "iot.sixiang.license.mapper")
@ComponentScan(basePackages = {"iot.sixiang.license", "com.acc"})
public class LicenseApplication implements WebMvcConfigurer { public class LicenseApplication implements WebMvcConfigurer {
@Override @Override
......
...@@ -54,5 +54,4 @@ public class BalanceManager { ...@@ -54,5 +54,4 @@ public class BalanceManager {
return servers.get(index); return servers.get(index);
} }
} }
} }
...@@ -3,6 +3,7 @@ package iot.sixiang.license.config; ...@@ -3,6 +3,7 @@ package iot.sixiang.license.config;
import iot.sixiang.license.jwt.AuthenticationInterceptor; import iot.sixiang.license.jwt.AuthenticationInterceptor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*; import org.springframework.web.servlet.config.annotation.*;
...@@ -14,11 +15,17 @@ public class CorsConfig implements WebMvcConfigurer { ...@@ -14,11 +15,17 @@ public class CorsConfig implements WebMvcConfigurer {
@Autowired @Autowired
AuthenticationInterceptor authenticationInterceptor; AuthenticationInterceptor authenticationInterceptor;
@Value("${cros.cros_allowed_origins}")
private String[] allowedOrigins;
@Value("${cros.cros_allowed_method}")
private String[] allowedMethods;
@Override @Override
public void addCorsMappings(CorsRegistry registry) { public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") registry.addMapping("/**")
.allowedOrigins("*") .allowedOrigins(allowedOrigins)
.allowedMethods("*") .allowedMethods(allowedMethods)
.allowCredentials(true) .allowCredentials(true)
.maxAge(3600) .maxAge(3600)
.allowedHeaders("*"); .allowedHeaders("*");
......
package iot.sixiang.license.config;
/**
* Title: ThreadPoolConfig
* Description:
*
* @author tianlai3
* @date 2022-07-16 20:05:38
*/
import lombok.Data;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Data
@Configuration
@EnableAsync
public class ThreadPoolConfig {
private static final int corePoolSize = 1; // 核心线程数(默认线程数)
private static final int maxPoolSize = 2; // 最大线程数
private static final int keepAliveTime = 10; // 允许线程空闲时间(单位:默认为秒)
private static final int queueCapacity = 2; // 缓冲队列数
/**
* 默认异步线程池
*
* @return
*/
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setThreadNamePrefix("threadPoll-");
pool.setCorePoolSize(corePoolSize);
pool.setMaxPoolSize(maxPoolSize);
pool.setKeepAliveSeconds(keepAliveTime);
pool.setQueueCapacity(queueCapacity);
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
pool.initialize();
return pool;
}
}
...@@ -16,7 +16,10 @@ import iot.sixiang.license.model.PageInfoModel; ...@@ -16,7 +16,10 @@ import iot.sixiang.license.model.PageInfoModel;
import iot.sixiang.license.model.PageResult; import iot.sixiang.license.model.PageResult;
import iot.sixiang.license.model.vo.AppVo; import iot.sixiang.license.model.vo.AppVo;
import iot.sixiang.license.service.ApplyService; import iot.sixiang.license.service.ApplyService;
import iot.sixiang.license.xss.XssUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
...@@ -37,18 +40,24 @@ public class ApplyController { ...@@ -37,18 +40,24 @@ public class ApplyController {
@Autowired @Autowired
private ApplyService applyService; private ApplyService applyService;
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields(new String[]{"adminCome"});
}
/** /**
* 添加apply * 添加apply
*
* @param jsonObject * @param jsonObject
* @return * @return
*/ */
@ApiOperation(value = "应用添加接口", notes = "用于添加应用") @ApiOperation(value = "应用添加接口", notes = "用于添加应用")
@PostMapping("add") @PostMapping("add")
@MyLog(title = "添加应用", optParam = "#{jsonObject}", businessType = BusinessType.INSERT) @MyLog(title = "添加应用", optParam = "#{jsonObject}", businessType = BusinessType.INSERT)
@ApiOperationSupport(params = @DynamicParameters(name = "jsonObject",properties = { @ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = {
@DynamicParameter(name = "appName",value = "应用名",required = true,dataTypeClass = String.class), @DynamicParameter(name = "appName", value = "应用名", required = true, dataTypeClass = String.class),
@DynamicParameter(name = "appKey",value = "应用key",required = true,dataTypeClass = String.class), @DynamicParameter(name = "appKey", value = "应用key", required = true, dataTypeClass = String.class),
@DynamicParameter(name = "userId",value = "用户Id",required = true,dataTypeClass = Integer.class) @DynamicParameter(name = "userId", value = "用户Id", required = true, dataTypeClass = Integer.class)
})) }))
public BaseResult addApply(@RequestBody JSONObject jsonObject) { public BaseResult addApply(@RequestBody JSONObject jsonObject) {
String appName = jsonObject.getString("appName"); String appName = jsonObject.getString("appName");
...@@ -64,6 +73,7 @@ public class ApplyController { ...@@ -64,6 +73,7 @@ public class ApplyController {
/** /**
* 分页查询所有的apply * 分页查询所有的apply
*
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @return * @return
...@@ -72,21 +82,26 @@ public class ApplyController { ...@@ -72,21 +82,26 @@ public class ApplyController {
@GetMapping("list") @GetMapping("list")
@MyLog(title = "获取应用列表", optParam = "#{pageNo},#{pageSize},#{appName}", businessType = BusinessType.SELECT) @MyLog(title = "获取应用列表", optParam = "#{pageNo},#{pageSize},#{appName}", businessType = BusinessType.SELECT)
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "pageNo",value = "当前在第几页", required = true, dataType = "int"), @ApiImplicitParam(name = "pageNo", value = "当前在第几页", required = true, dataType = "int"),
@ApiImplicitParam(name = "pageSize",value = "每页显示多少页", required = true, dataType = "int"), @ApiImplicitParam(name = "pageSize", value = "每页显示多少页", required = true, dataType = "int"),
@ApiImplicitParam(name = "appName",value = "应用名") @ApiImplicitParam(name = "appName", value = "应用名")
}) })
public PageResult<AppVo> getAppList(@RequestParam(value = "pageNo", defaultValue = "0") int pageNo, public PageResult<AppVo> getAppList(@RequestParam(value = "pageNo", defaultValue = "0") int pageNo,
@RequestParam(value = "pageSize", defaultValue = "0") int pageSize, @RequestParam(value = "pageSize", defaultValue = "0") int pageSize,
@RequestParam(value = "appName",required = false) String appName) { @RequestParam(value = "appName", required = false) String appName) {
PageInfoModel<AppVo> records = applyService.getAppList(pageNo,pageSize,appName); appName = XssUtil.checkXSS(appName);
PageInfoModel<AppVo> records = applyService.getAppList(pageNo, pageSize, appName);
int total = records.getTotal(); int total = records.getTotal();
int pages = total/pageSize;//pages为总页数 int pages = total / pageSize;//pages为总页数
int mod = total%pageSize; int mod = total % pageSize;
if(mod!=0){ if (mod != 0) {
pages = pages +1; pages = pages + 1;
} }
List<AppVo> result = records.getResult(); List<AppVo> result = records.getResult();
return new PageResult(200,"查找成功",pageNo,pages,total,result); String str = "n647dBvogC5ps9r0zePShkExRMGyIZlqFUuWNL1Qt8XVja3A";
for (AppVo u : result) {
u.setAppKey(DigestUtils.md5DigestAsHex(((str + u.getAppKey()).getBytes())));
}
return new PageResult(200, "查找成功", pageNo, pages, total, result);
} }
} }
\ No newline at end of file
...@@ -5,7 +5,10 @@ import com.alibaba.fastjson.JSONObject; ...@@ -5,7 +5,10 @@ import com.alibaba.fastjson.JSONObject;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.DynamicParameter; import com.github.xiaoymin.knife4j.annotations.DynamicParameter;
import com.github.xiaoymin.knife4j.annotations.DynamicParameters; import com.github.xiaoymin.knife4j.annotations.DynamicParameters;
import io.swagger.annotations.*; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import iot.sixiang.license.device.DeviceManager; import iot.sixiang.license.device.DeviceManager;
import iot.sixiang.license.entity.DeviceBlack; import iot.sixiang.license.entity.DeviceBlack;
import iot.sixiang.license.log.BusinessType; import iot.sixiang.license.log.BusinessType;
...@@ -17,8 +20,16 @@ import iot.sixiang.license.model.vo.DeviceDetailVo; ...@@ -17,8 +20,16 @@ import iot.sixiang.license.model.vo.DeviceDetailVo;
import iot.sixiang.license.model.vo.DeviceVo; import iot.sixiang.license.model.vo.DeviceVo;
import iot.sixiang.license.service.DeviceBlackService; import iot.sixiang.license.service.DeviceBlackService;
import iot.sixiang.license.service.DeviceService; import iot.sixiang.license.service.DeviceService;
import iot.sixiang.license.xss.XssUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
...@@ -43,6 +54,11 @@ public class DeviceController { ...@@ -43,6 +54,11 @@ public class DeviceController {
@Autowired @Autowired
private DeviceBlackService deviceBlackService; private DeviceBlackService deviceBlackService;
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields(new String[]{"adminCome"});
}
/** /**
* 添加device * 添加device
* *
...@@ -51,10 +67,7 @@ public class DeviceController { ...@@ -51,10 +67,7 @@ public class DeviceController {
*/ */
@ApiOperation(value = "添加设备接口", notes = "用于添加设备") @ApiOperation(value = "添加设备接口", notes = "用于添加设备")
@PostMapping("add") @PostMapping("add")
@ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = { @ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = {@DynamicParameter(name = "appId", value = "应用Id", required = true, dataTypeClass = String.class), @DynamicParameter(name = "count", value = "需要创建的设备数量", required = true, dataTypeClass = Integer.class),}))
@DynamicParameter(name = "appId", value = "应用Id", required = true, dataTypeClass = String.class),
@DynamicParameter(name = "count", value = "需要创建的设备数量", required = true, dataTypeClass = Integer.class),
}))
@MyLog(title = "添加设备", optParam = "#{jsonObject}", businessType = BusinessType.INSERT) @MyLog(title = "添加设备", optParam = "#{jsonObject}", businessType = BusinessType.INSERT)
public BaseResult addDevice(@RequestBody JSONObject jsonObject) { public BaseResult addDevice(@RequestBody JSONObject jsonObject) {
String appId = jsonObject.getString("appId"); String appId = jsonObject.getString("appId");
...@@ -93,6 +106,8 @@ public class DeviceController { ...@@ -93,6 +106,8 @@ public class DeviceController {
@RequestParam(value = "userName", required = false) String userName, @RequestParam(value = "userName", required = false) String userName,
@RequestParam(value = "sn", required = false) String sn, @RequestParam(value = "sn", required = false) String sn,
@RequestParam(value = "status", required = false) Integer status) { @RequestParam(value = "status", required = false) Integer status) {
appName = XssUtil.checkXSS(appName);
userName = XssUtil.checkXSS(userName);
PageInfoModel<DeviceVo> records = deviceService.getDeviceList(pageNo, pageSize, appName, userName, sn, status); PageInfoModel<DeviceVo> records = deviceService.getDeviceList(pageNo, pageSize, appName, userName, sn, status);
int total = records.getTotal(); int total = records.getTotal();
int pages = total / pageSize;//pages为总页数 int pages = total / pageSize;//pages为总页数
...@@ -107,17 +122,10 @@ public class DeviceController { ...@@ -107,17 +122,10 @@ public class DeviceController {
@ApiOperation(value = "获取设备详细信息接口", notes = "用于获取设备详细信息列表") @ApiOperation(value = "获取设备详细信息接口", notes = "用于获取设备详细信息列表")
@GetMapping("detail/list") @GetMapping("detail/list")
@MyLog(title = "获取设备详细信息接口", optParam = "#{pageNo},#{pageSize},#{appName},#{userName}", businessType = BusinessType.SELECT) @MyLog(title = "获取设备详细信息接口", optParam = "#{pageNo},#{pageSize},#{appName},#{userName}", businessType = BusinessType.SELECT)
@ApiImplicitParams({ @ApiImplicitParams({@ApiImplicitParam(name = "pageNo", value = "当前在第几页", required = true, dataType = "int"), @ApiImplicitParam(name = "pageSize", value = "每页显示多少条", required = true, dataType = "int"), @ApiImplicitParam(name = "appName", value = "应用名"), @ApiImplicitParam(name = "userName", value = "用户名")})
@ApiImplicitParam(name = "pageNo", value = "当前在第几页", required = true, dataType = "int"), public PageResult<DeviceDetailVo> getDeviceDetailList(@RequestParam(value = "pageNo", defaultValue = "0") int pageNo, @RequestParam(value = "pageSize", defaultValue = "0") int pageSize, @RequestParam(value = "appName", required = false) String appName, @RequestParam(value = "userName", required = false) String userName) {
@ApiImplicitParam(name = "pageSize", value = "每页显示多少条", required = true, dataType = "int"), appName = XssUtil.checkXSS(appName);
@ApiImplicitParam(name = "appName", value = "应用名"), userName = XssUtil.checkXSS(userName);
@ApiImplicitParam(name = "userName", value = "用户名")
})
public PageResult<DeviceDetailVo> getDeviceDetailList(@RequestParam(value = "pageNo", defaultValue = "0") int pageNo,
@RequestParam(value = "pageSize", defaultValue = "0") int pageSize,
@RequestParam(value = "appName", required = false) String appName,
@RequestParam(value = "userName", required = false) String userName) {
PageInfoModel<DeviceDetailVo> records = deviceManager.getDeviceDetailList(pageNo, pageSize, appName, userName); PageInfoModel<DeviceDetailVo> records = deviceManager.getDeviceDetailList(pageNo, pageSize, appName, userName);
int total = records.getTotal(); int total = records.getTotal();
int pages = total / pageSize;//pages为总页数 int pages = total / pageSize;//pages为总页数
...@@ -137,9 +145,7 @@ public class DeviceController { ...@@ -137,9 +145,7 @@ public class DeviceController {
*/ */
@ApiOperation(value = "添加设备黑名单接口", notes = "用于添加设备黑名单") @ApiOperation(value = "添加设备黑名单接口", notes = "用于添加设备黑名单")
@PostMapping("device_black/add") @PostMapping("device_black/add")
@ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = { @ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = {@DynamicParameter(name = "deviceId", value = "设备Id", required = true, dataTypeClass = Integer.class)}))
@DynamicParameter(name = "deviceId", value = "设备Id", required = true, dataTypeClass = Integer.class)
}))
@MyLog(title = "添加设备黑名单", optParam = "#{jsonObject}", businessType = BusinessType.INSERT) @MyLog(title = "添加设备黑名单", optParam = "#{jsonObject}", businessType = BusinessType.INSERT)
public BaseResult addDeviceBlack(@RequestBody JSONObject jsonObject) { public BaseResult addDeviceBlack(@RequestBody JSONObject jsonObject) {
int deviceId = jsonObject.getIntValue("deviceId"); int deviceId = jsonObject.getIntValue("deviceId");
...@@ -159,9 +165,7 @@ public class DeviceController { ...@@ -159,9 +165,7 @@ public class DeviceController {
*/ */
@ApiOperation(value = "设备黑名单删除接口", notes = "删除设备黑名单") @ApiOperation(value = "设备黑名单删除接口", notes = "删除设备黑名单")
@PostMapping("device_black/delete") @PostMapping("device_black/delete")
@ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = { @ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = {@DynamicParameter(name = "deviceId", value = "设备Id", required = true, dataTypeClass = Integer.class)}))
@DynamicParameter(name = "deviceId", value = "设备Id", required = true, dataTypeClass = Integer.class)
}))
@MyLog(title = "删除设备黑名单", optParam = "#{deviceId}", businessType = BusinessType.DELETE) @MyLog(title = "删除设备黑名单", optParam = "#{deviceId}", businessType = BusinessType.DELETE)
public BaseResult deleteDeviceBlack(@RequestBody JSONObject jsonObject) { public BaseResult deleteDeviceBlack(@RequestBody JSONObject jsonObject) {
int deviceId = jsonObject.getIntValue("deviceId"); int deviceId = jsonObject.getIntValue("deviceId");
...@@ -183,10 +187,7 @@ public class DeviceController { ...@@ -183,10 +187,7 @@ public class DeviceController {
@ApiOperation(value = "获取设备黑名单列表接口", notes = "用于获取设备黑名单列表") @ApiOperation(value = "获取设备黑名单列表接口", notes = "用于获取设备黑名单列表")
@GetMapping("device_black/list") @GetMapping("device_black/list")
@MyLog(title = "获取设备黑名单列表", optParam = "#{pageNo},#{pageSize}", businessType = BusinessType.SELECT) @MyLog(title = "获取设备黑名单列表", optParam = "#{pageNo},#{pageSize}", businessType = BusinessType.SELECT)
@ApiImplicitParams({ @ApiImplicitParams({@ApiImplicitParam(name = "pageNo", value = "当前在第几页", required = true, dataType = "int"), @ApiImplicitParam(name = "pageSize", value = "每页显示多少页", required = true, dataType = "int")})
@ApiImplicitParam(name = "pageNo", value = "当前在第几页", required = true, dataType = "int"),
@ApiImplicitParam(name = "pageSize", value = "每页显示多少页", required = true, dataType = "int")
})
public PageResult<DeviceBlack> getDeviceBlackList(@RequestParam(value = "pageNo", defaultValue = "0") int pageNo, @RequestParam(value = "pageSize", defaultValue = "0") int pageSize) { public PageResult<DeviceBlack> getDeviceBlackList(@RequestParam(value = "pageNo", defaultValue = "0") int pageNo, @RequestParam(value = "pageSize", defaultValue = "0") int pageSize) {
PageInfoModel<DeviceBlack> records = deviceBlackService.getDeviceBlackList(pageNo, pageSize); PageInfoModel<DeviceBlack> records = deviceBlackService.getDeviceBlackList(pageNo, pageSize);
int total = records.getTotal(); int total = records.getTotal();
......
package iot.sixiang.license.controller;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SM4;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import iot.sixiang.license.model.ResResult;
import iot.sixiang.license.model.vo.EncryptVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
/**
* Title: EncryptController
* Description: TODO
*
* @author tianlai3
* @date 2022-07-13 01:05:23
*/
@Slf4j
@RestController
@RequestMapping("/iot_license")
@Api(value = "数据加密", tags = {"数据加密"})
public class EncryptController {
@Value("${other.sm4-key}")
private String sm4Key;
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields(new String[]{"adminCome"});
}
@ApiOperation(value = "数据加密")
@PostMapping("/encrypt")
public ResResult<EncryptVo> encrypt(@RequestBody EncryptVo encryptVo) {
if (StringUtils.isEmpty(encryptVo.getMessage())) {
return ResResult.failed().setMsgValue("输入的信息不能为空");
}
SM4 sm4 = SmUtil.sm4(sm4Key.getBytes());
EncryptVo vo = new EncryptVo();
vo.setMessage(sm4.encryptBase64(encryptVo.getMessage()));
return ResResult.success().goRecord(vo);
}
@ApiOperation(value = "数据解密")
@PostMapping("/decrypt")
public ResResult<EncryptVo> decrypt(@RequestBody EncryptVo encryptVo) {
if (StringUtils.isEmpty(encryptVo.getMessage())) {
return ResResult.failed().setMsgValue("输入的信息不能为空");
}
SM4 sm4 = SmUtil.sm4(sm4Key.getBytes());
String message = sm4.decryptStr(encryptVo.getMessage());
EncryptVo vo = new EncryptVo();
vo.setMessage(message);
return ResResult.success().goRecord(vo);
}
}
package iot.sixiang.license.controller; package iot.sixiang.license.controller;
import com.acc.secret.util.RSAUtil;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import iot.sixiang.license.consts.ResultCode;
import iot.sixiang.license.entity.User;
import iot.sixiang.license.jwt.JwtUtil; import iot.sixiang.license.jwt.JwtUtil;
import iot.sixiang.license.jwt.LoginUser; import iot.sixiang.license.jwt.LoginUser;
import iot.sixiang.license.jwt.UserUtils;
import iot.sixiang.license.log.BusinessType; import iot.sixiang.license.log.BusinessType;
import iot.sixiang.license.log.MyLog; import iot.sixiang.license.log.MyLog;
import iot.sixiang.license.mapper.UserMapper;
import iot.sixiang.license.model.BaseResult; import iot.sixiang.license.model.BaseResult;
import iot.sixiang.license.model.ResResult; import iot.sixiang.license.model.ResResult;
import iot.sixiang.license.model.dto.CheckCodeDto;
import iot.sixiang.license.model.vo.LoginReqVo;
import iot.sixiang.license.model.vo.LoginVo; import iot.sixiang.license.model.vo.LoginVo;
import iot.sixiang.license.model.vo.UserResetPwdVo;
import iot.sixiang.license.service.UserService;
import iot.sixiang.license.util.CommonUtil;
import iot.sixiang.license.util.EmailUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore; import springfox.documentation.annotations.ApiIgnore;
import java.util.HashMap; import javax.annotation.Resource;
import java.util.Map; import javax.servlet.ServletRequest;
import java.util.Date;
/** /**
* 登录Controller * 登录Controller
*/ */
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/") @RequestMapping("/iot_license")
@Api(value = "登录模块", tags = {"登录模块"}) @Api(value = "登录模块", tags = {"登录模块"})
public class LoginController { public class LoginController {
//模拟数据库 @Resource
static Map<String, LoginUser> userMap = new HashMap<>(); EmailUtils emailUtils;
@Resource
UserMapper userMapper;
@Resource
UserService userService;
static { @Value("${spring.mail.to}")
LoginUser user1 = new LoginUser("2147483647", "root", "123456"); private String account;
userMap.put("2147483647", user1); @Value("${rsa.private_key}")
} private String PRIVATE_KRY;
@Value("${other.error_count.forget_pwd}")
private Integer forgetPwdMaxErrCount;
@Value("${other.error_count.check_code}")
private Integer checkCodeMaxErrCount;
@Value("${other.code_exp_time}")
private Integer codeExpTimeStr;
private static final String USER_NAME = "root";
private static final String OPERATION_CHECK = "check";
private static final String OPERATION_RESET = "reset";
/** /**
* 模拟用户登录 * 模拟用户登录
*/ */
@ApiOperation(value = "登录接口", notes = "登录接口") @ApiOperation(value = "登录接口", notes = "登录接口")
@GetMapping("login") @PostMapping("login")
@MyLog(title = "登录", optParam = "#{userName},#{password}", businessType = BusinessType.OTHER) @MyLog(title = "登录", businessType = BusinessType.OTHER)
@ApiImplicitParams({ public ResResult<LoginVo> login(@RequestBody LoginReqVo loginReqVo) {
@ApiImplicitParam(name = "userName", value = "用户名", required = true), String userName = loginReqVo.getUserName();
@ApiImplicitParam(name = "password", value = "密码", required = true) String password = loginReqVo.getPassword();
}) String code = loginReqVo.getCode();
public ResResult<LoginVo> login(@RequestParam("userName") String userName, @RequestParam("password") String password) { if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(password) || StringUtils.isEmpty(code)) {
for (LoginUser dbUser : userMap.values()) { return ResResult.validate_failed().setMsgValue("参数不能为空");
if (dbUser.getUserName().equals(userName) && dbUser.getPassword().equals(password)) { }
log.info("登录成功!生成token!"); User user = userMapper.getUserByUserName(USER_NAME);
String name = USER_NAME;
String pwd = user.getPassword();
LoginUser dbUser = new LoginUser(String.valueOf(user.getUserId()), user.getUserName(), user.getPassword());
if (name.equals(userName) && RSAUtil.getDecryptString(password, PRIVATE_KRY).equals(pwd)) {
// 登录错误次数
Integer errCnt = UserUtils.getErrCnt(userName);
Date countFreezeDate = UserUtils.getCountFreezeDate(userName);
Date curDate = new Date();
if (errCnt != null && errCnt >= 3 && countFreezeDate != null && curDate.before(countFreezeDate)) {
return ResResult.failed().setMsgValue("用户名或密码错误次数达到三次,请三分钟后再重试");
} else {
Date curCodeDate = new Date();
if (code.equals(UserUtils.getEmailCode(account)) && curCodeDate.before(UserUtils.getEmailCodeExpTime(account))) {
//if (code.equals("123456")) {
String token = JwtUtil.createToken(dbUser); String token = JwtUtil.createToken(dbUser);
LoginVo loginVo = new LoginVo(); LoginVo loginVo = new LoginVo();
loginVo.setAuthorization(token); loginVo.setAuthorization(token);
return ResResult.success().record(loginVo); loginVo.setUpdateTime(user.getUpdateTime());
UserUtils.setToken(dbUser.getUserId(), token);
UserUtils.setTokenExp(dbUser.getUserId(), JwtUtil.getTokenExp());
UserUtils.removeErrCnt(userName);
UserUtils.removeCountFreezeDate(userName);
UserUtils.removeEmailCode(account);
UserUtils.removeEmailCodeExpTime(account);
log.info("登录成功!生成token!");
return ResResult.success().goRecord(loginVo);
} else {
return ResResult.failed().setMsgValue("验证码错误或已过期");
}
} }
} }
return ResResult.failed().msg("用户名或密码错误"); Integer errCnt = UserUtils.getErrCnt(userName);
if (errCnt == null) {
UserUtils.setErrCnt(userName, 1);
} else {
if (errCnt == 1) {
UserUtils.setErrCnt(userName, ++errCnt);
} else if (errCnt == 2) {
UserUtils.setErrCnt(userName, ++errCnt);
Date freezeDate = new Date(System.currentTimeMillis() + 3 * 60 * 1000);
UserUtils.setCountFreezeDate(userName, freezeDate);
} else {
Date countFreezeDate = UserUtils.getCountFreezeDate(userName);
Date curDate = new Date();
if (curDate.before(countFreezeDate)) {
return ResResult.failed().setMsgValue("用户名或密码错误次数达到三次,请三分钟后再重试");
} else {
UserUtils.setErrCnt(userName, 1);
Date freezeDate = new Date(System.currentTimeMillis() + 3 * 60 * 1000);
UserUtils.setCountFreezeDate(userName, freezeDate);
}
}
}
return ResResult.failed().setMsgValue("用户名或密码错误");
} }
//public static void main(String[] args) {
// System.out.println(DigestUtils.md5DigestAsHex("PI7dBYlEfeP8IZ6vogqFL1U5pVnyCuNAGja3lsREx4M9r0SX123456PI7dBYlEfeP8IZ6vogqFL1U5pVnyCuNAGja3lsREx4M9r0SX".getBytes()));
// System.out.println(DigestUtils.md5DigestAsHex("PI7dBYlEfeP8IZ6vogqFL1U5pVnyCuNAGja3lsREx4M9r0SXrootPI7dBYlEfeP8IZ6vogqFL1U5pVnyCuNAGja3lsREx4M9r0SX".getBytes()));
//}
@ApiOperation(value = "注销接口", notes = "注销接口") @ApiOperation(value = "注销接口", notes = "注销接口")
@GetMapping("logout") @GetMapping("logout")
@MyLog(title = "注销", businessType = BusinessType.OTHER) @MyLog(title = "注销", businessType = BusinessType.OTHER)
public BaseResult logout() { public BaseResult logout() {
String loginUserId = UserUtils.getLoginUserId();
UserUtils.removeToken(loginUserId);
UserUtils.removeTokenExp(loginUserId);
return BaseResult.success(); return BaseResult.success();
} }
@RequestMapping(value = "fail", method = {RequestMethod.GET, RequestMethod.POST}) @RequestMapping(value = "fail", method = {RequestMethod.GET, RequestMethod.POST})
@ApiIgnore @ApiIgnore
public BaseResult fail() { public BaseResult fail(ServletRequest servletRequest) {
String msg = servletRequest.getAttribute("msg").toString();
return BaseResult.failed().setCodeValue(ResultCode.UNAUTHORIZED.getCode()).setMsgValue(msg);
}
@ApiOperation(value = "发送验证码", notes = "发送验证码到邮箱")
@GetMapping("send_code")
public BaseResult sendCode() {
Date emailCodeExpTime = UserUtils.getEmailCodeExpTime(account);
if (emailCodeExpTime != null && emailCodeExpTime.after(new Date())) {
return BaseResult.failed().setMsgValue("验证码还在有效期内");
}
String code = CommonUtil.getValidateCode();
String content = "感谢您使用实名制服务器" + "\n" + "此次登录验证码为:" + code + "(有效期" + codeExpTimeStr + "分钟)。验证码提供给他人可能导致账号被盗,请勿转发或泄露。" + "\n" + "--------------------------------------------------------------" + "此邮件由系统自动发送,请勿回复此邮件" + "--------------------------------------------------------------";
emailUtils.sendSimpleMail(account, "感谢您使用实名制服务器", content);
UserUtils.setEmailCode(account, code);
Date codeExpTime = new Date(System.currentTimeMillis() + codeExpTimeStr * 60 * 1000);
UserUtils.setEmailCodeExpTime(account, codeExpTime);
return BaseResult.success();
}
@ApiOperation(value = "发送修改密码验证码", notes = "发送修改密码验证码到邮箱")
@GetMapping("send_code/change_pwd")
public BaseResult sendChangePwdCode() {
Date emailCodeExpTime = UserUtils.getEmailCodeExpTime(account + OPERATION_CHECK);
if (emailCodeExpTime != null && emailCodeExpTime.after(new Date())) {
return BaseResult.failed().setMsgValue("验证码还在有效期内");
}
String code = CommonUtil.getValidateCode();
String content = "感谢您使用实名制服务器" + "\n" + "此次修改密码的验证码为:" + code + "(有效期" + codeExpTimeStr + "分钟)。验证码提供给他人可能导致账号被盗,请勿转发或泄露。" + "\n" + "--------------------------------------------------------------" + "此邮件由系统自动发送,请勿回复此邮件" + "--------------------------------------------------------------";
emailUtils.sendSimpleMail(account, "感谢您使用实名制服务器", content);
UserUtils.setEmailCode(account + OPERATION_CHECK, code);
Date codeExpTime = new Date(System.currentTimeMillis() + codeExpTimeStr * 60 * 1000);
UserUtils.setEmailCodeExpTime(account + OPERATION_CHECK, codeExpTime);
return BaseResult.success();
}
@ApiOperation(value = "校验验证码", notes = "校验验证码")
@PostMapping("check_code")
public BaseResult checkCode(@RequestBody CheckCodeDto checkCodeDto) {
String code = checkCodeDto.getCode();
String emailCode = UserUtils.getEmailCode(account + OPERATION_CHECK);
String codeFreezeTimeStr = UserUtils.getCodeFreezeTimeMap(account + OPERATION_CHECK);
// codeFreezeTimeStr不为空且冻结时间是今天直接报错,不是今天的话清空数据
if (!StringUtils.isEmpty(codeFreezeTimeStr)) {
if (codeFreezeTimeStr.equals(CommonUtil.getCurDateStr())) {
return BaseResult.failed().setMsgValue("今日校验次数已达" + checkCodeMaxErrCount + "次,请明日再试");
} else {
UserUtils.removeCodeErrCntMap(account + OPERATION_CHECK);
UserUtils.removeCodeFreezeTimeMap(account + OPERATION_CHECK);
}
}
Date emailCodeExpTime = UserUtils.getEmailCodeExpTime(account + OPERATION_CHECK);
if (StringUtils.isEmpty(code)) {
return BaseResult.failed().setMsgValue("验证码不能为空");
} else {
Integer codeErrCnt = UserUtils.getCodeErrCntMap(account + OPERATION_CHECK);
if (codeErrCnt == null) {
codeErrCnt = 0;
}
if (emailCodeExpTime == null || emailCodeExpTime.before(new Date())) {
if (codeErrCnt < checkCodeMaxErrCount - 1) {
UserUtils.setCodeErrCntMap(account + OPERATION_CHECK, codeErrCnt + 1);
} else {
UserUtils.setCodeFreezeTimeMap(account + OPERATION_CHECK, CommonUtil.getCurDateStr());
}
return BaseResult.failed().setMsgValue("验证码已过期,请重发");
}
if (!code.equals(emailCode)) {
if (codeErrCnt < checkCodeMaxErrCount - 1) {
UserUtils.setCodeErrCntMap(account + OPERATION_CHECK, codeErrCnt + 1);
} else {
UserUtils.setCodeFreezeTimeMap(account + OPERATION_CHECK, CommonUtil.getCurDateStr());
}
return BaseResult.failed().setMsgValue("验证码不正确,请重试");
} else {
return BaseResult.success();
}
}
}
return BaseResult.unauthorized(); @ApiOperation(value = "重置密码", notes = "重置密码功能")
@PostMapping("reset_pwd")
@MyLog(title = "重置密码", businessType = BusinessType.UPDATE)
public BaseResult resetPwd(@RequestBody UserResetPwdVo userResetPwdVo) {
String errCntTimeMap = UserUtils.getErrCntTimeMap(account + OPERATION_RESET);
if (!StringUtils.isEmpty(errCntTimeMap)) {
if (errCntTimeMap.equals(CommonUtil.getCurDateStr())) {
return BaseResult.failed().setMsgValue("今日尝试重置密码次数已达" + forgetPwdMaxErrCount + "次,请明日再试");
} else {
UserUtils.removeErrCntTimeMap(account + OPERATION_RESET);
UserUtils.removeErrCnt(account + OPERATION_RESET);
}
}
String newPassWord = userResetPwdVo.getPassword();
newPassWord = RSAUtil.getDecryptString(newPassWord, PRIVATE_KRY);
if (StringUtils.isEmpty(newPassWord)) {
return BaseResult.failed().setMsgValue("密码不能为空");
}
Integer errCnt = UserUtils.getErrCnt(account + OPERATION_RESET);
if (errCnt == null) {
errCnt = 0;
}
User user = userService.getUserByName(USER_NAME);
if (newPassWord.length() < 8) {
computeResetPwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码不得小于8位");
}
if (CommonUtil.verifyPasswordContainAccount(newPassWord, user.getUserName())) {
computeResetPwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码中不得包含用户名的完整字符串、大小写变位或形似变换的字符串");
}
if (CommonUtil.isKeyBoardContinuousChar(newPassWord)) {
computeResetPwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码不得包含键盘连续字符4个及以上");
}
if (!CommonUtil.checkPassword(newPassWord)) {
computeResetPwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("至少由大写字母、小写字母、数字与特殊符号等4类中3类混合");
}
user.setPassword(newPassWord);
boolean b = userService.updateUser(user);
if (b) {
return BaseResult.success().setMsgValue("密码修改成功");
} else {
return BaseResult.failed().setMsgValue("密码修改失败");
}
}
private void computeResetPwdErrCnt(int errCnt) {
if (errCnt < forgetPwdMaxErrCount - 1) {
UserUtils.setErrCnt(account + OPERATION_RESET, errCnt + 1);
} else {
UserUtils.setErrCntTimeMap(account + OPERATION_RESET, CommonUtil.getCurDateStr());
}
} }
} }
package iot.sixiang.license.controller;
import cn.hutool.core.util.IdcardUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import iot.sixiang.license.model.ResResult;
import iot.sixiang.license.model.vo.MaskingVo;
import iot.sixiang.license.util.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.owasp.esapi.ESAPI;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
/**
* Title: MaskingController
* Description: TODO
*
* @author tianlai3
* @date 2022-07-13 01:40:24
*/
@Slf4j
@RestController
@RequestMapping("/iot_license")
@Api(value = "数据脱敏", tags = {"数据脱敏"})
public class MaskingController {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields(new String[]{"adminCome"});
}
@ApiOperation(value = "数据脱敏")
@PostMapping("/desensitize")
public ResResult<MaskingVo> encrypt(@RequestBody MaskingVo maskingVo) {
if (!IdcardUtil.isValidCard(maskingVo.getIdCard())) {
return ResResult.failed().setMsgValue("身份证格式出错");
}
if (StringUtils.isEmpty(maskingVo.getUserName())) {
return ResResult.failed().setMsgValue("用户姓名不能为空");
}
MaskingVo vo = new MaskingVo();
vo.setUserName(ESAPI.encoder().encodeForDN(CommonUtil.nameDesensitization(maskingVo.getUserName())));
vo.setIdCard(ESAPI.encoder().encodeForDN(CommonUtil.idCardEncrypt(maskingVo.getIdCard())));
return ResResult.success().goRecord(vo);
}
}
...@@ -25,10 +25,15 @@ import iot.sixiang.license.service.AlarmReadService; ...@@ -25,10 +25,15 @@ import iot.sixiang.license.service.AlarmReadService;
import iot.sixiang.license.service.AlarmService; import iot.sixiang.license.service.AlarmService;
import iot.sixiang.license.service.MonitorService; import iot.sixiang.license.service.MonitorService;
import iot.sixiang.license.service.ServerService; import iot.sixiang.license.service.ServerService;
import iot.sixiang.license.xss.BeanCopyUtil;
import iot.sixiang.license.xss.XssUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.owasp.esapi.ESAPI;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -52,12 +57,17 @@ public class OperateController { ...@@ -52,12 +57,17 @@ public class OperateController {
@Autowired @Autowired
private ForwardManager forwardManager; private ForwardManager forwardManager;
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields(new String[]{"adminCome"});
}
@ApiOperation(value = "服务接口", notes = "用于获取服务列表") @ApiOperation(value = "服务接口", notes = "用于获取服务列表")
@GetMapping("monitor/server") @GetMapping("monitor/server")
@MyLog(title = "获取服务列表", businessType = BusinessType.SELECT) @MyLog(title = "获取服务列表", businessType = BusinessType.SELECT)
public ResResult<SamMonitor> getDeviceTypes() { public ResResult<SamMonitor> getDeviceTypes() {
List<SamMonitor> records = operateManager.getSamMonitorList(); List<SamMonitor> records = operateManager.getSamMonitorList();
return ResResult.success().record(records); return ResResult.success().goRecord(records);
} }
...@@ -71,10 +81,10 @@ public class OperateController { ...@@ -71,10 +81,10 @@ public class OperateController {
@ApiOperation(value = "获取并发量接口", notes = "用于获取并发量") @ApiOperation(value = "获取并发量接口", notes = "用于获取并发量")
@GetMapping("monitor/qps") @GetMapping("monitor/qps")
@MyLog(title = "获取并发量", optParam = "#{type}", businessType = BusinessType.SELECT) @MyLog(title = "获取并发量", optParam = "#{type}", businessType = BusinessType.SELECT)
@ApiImplicitParam(name = "type",value = "类型:0:今天 1:昨天 2:七天前 3:三十天前",required = true, dataType = "int") @ApiImplicitParam(name = "type", value = "类型:0:今天 1:昨天 2:七天前 3:三十天前", required = true, dataType = "int")
public ResResult<QpsVo> getQps(@RequestParam("type") int type) { public ResResult<QpsVo> getQps(@RequestParam("type") int type) {
HashMap<String, List<Integer>> monitorList = monitorService.getMonitorList(type); HashMap<String, List<Integer>> monitorList = monitorService.getMonitorList(type);
return ResResult.success().record(monitorList); return ResResult.success().goRecord(monitorList);
} }
@ApiOperation(value = "获取服务自诊断信息接口", notes = "用于获取服务诊断信息") @ApiOperation(value = "获取服务自诊断信息接口", notes = "用于获取服务诊断信息")
...@@ -83,7 +93,7 @@ public class OperateController { ...@@ -83,7 +93,7 @@ public class OperateController {
@ApiImplicitParam() @ApiImplicitParam()
public ResResult<ServerStatusVo> getDiagnosisInfo() { public ResResult<ServerStatusVo> getDiagnosisInfo() {
ServerStatusVo serverStatus = forwardManager.getServerStatus(); ServerStatusVo serverStatus = forwardManager.getServerStatus();
return ResResult.success().record(serverStatus); return ResResult.success().goRecord(serverStatus);
} }
...@@ -91,19 +101,20 @@ public class OperateController { ...@@ -91,19 +101,20 @@ public class OperateController {
@GetMapping("alarm/list") @GetMapping("alarm/list")
@MyLog(title = "获取告警列表", businessType = BusinessType.SELECT) @MyLog(title = "获取告警列表", businessType = BusinessType.SELECT)
public ResResult<List<AlarmVo>> getAlarmList() { public ResResult<List<AlarmVo>> getAlarmList() {
String userId = UserUtils.getLoginUserId(); String user = UserUtils.getLoginUserId();
int Id = Integer.valueOf(userId); int userI = Integer.valueOf(user);
List<AlarmVo> alarmList = alarmService.getAlarmList(Id); List<AlarmVo> alarmList = alarmService.getAlarmList(userI);
return ResResult.success().record(alarmList); List<AlarmVo> alarmVos = BeanCopyUtil.copyListProperties(alarmList, AlarmVo::new);
return ResResult.success().goRecord(alarmVos);
} }
@ApiOperation(value = "告警已读接口", notes = "将告警信息状态设为已读") @ApiOperation(value = "告警已读接口", notes = "将告警信息状态设为已读")
@PostMapping("alarm/read") @PostMapping("alarm/read")
@MyLog(title = "将告警信息状态设为已读", businessType = BusinessType.OTHER) @MyLog(title = "将告警信息状态设为已读", businessType = BusinessType.OTHER)
public BaseResult readAlarm(){ public BaseResult readAlarm() {
String id = UserUtils.getLoginUserId(); String i = UserUtils.getLoginUserId();
int userId = Integer.valueOf(id); int uI = Integer.valueOf(i);
boolean res = alarmReadService.readAlarm(userId); boolean res = alarmReadService.readAlarm(uI);
if (res) { if (res) {
return BaseResult.success(); return BaseResult.success();
} else { } else {
...@@ -116,35 +127,33 @@ public class OperateController { ...@@ -116,35 +127,33 @@ public class OperateController {
@MyLog(title = "统计sam总数", businessType = BusinessType.SELECT) @MyLog(title = "统计sam总数", businessType = BusinessType.SELECT)
public ResResult<SamVo> getSamTotalCount() { public ResResult<SamVo> getSamTotalCount() {
Map<String, SamMonitor> samMonitorMap = operateManager.getSamMonitorMap(); Map<String, SamMonitor> samMonitorMap = operateManager.getSamMonitorMap();
Map<String,Integer> map = new HashMap<>(); Map<String, Integer> map = new HashMap<>();
int totalSamCount = 0; int totalSamCount = 0;
int totalOnlineCount = 0; int totalOnlineCount = 0;
for (SamMonitor samMonitor: samMonitorMap.values()) { for (SamMonitor samMonitor : samMonitorMap.values()) {
totalSamCount += samMonitor.getSamCount(); totalSamCount += samMonitor.getSamCount();
totalOnlineCount += samMonitor.getOnlineCount(); totalOnlineCount += samMonitor.getOnlineCount();
} }
SamVo samVo = new SamVo(); SamVo samVo = new SamVo();
samVo.setTotalOnlineCount(totalOnlineCount); samVo.setTotalOnlineCount(totalOnlineCount);
samVo.setTotalSamCount(totalSamCount); samVo.setTotalSamCount(totalSamCount);
return ResResult.success().record(samVo); return ResResult.success().goRecord(samVo);
} }
/** /**
* 添加server * 添加server
*
* @param jsonObject * @param jsonObject
* @return * @return
*/ */
@ApiOperation(value = "添加服务接口", notes = "用于添加服务") @ApiOperation(value = "添加服务接口", notes = "用于添加服务")
@PostMapping("server/add") @PostMapping("server/add")
@MyLog(title = "添加服务", optParam = "#{jsonObject}", businessType = BusinessType.INSERT) @MyLog(title = "添加服务", optParam = "#{jsonObject}", businessType = BusinessType.INSERT)
@ApiOperationSupport(params = @DynamicParameters(name = "jsonObject",properties = { @ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = {@DynamicParameter(name = "serverIp", value = "服务Ip", required = true, dataTypeClass = String.class), @DynamicParameter(name = "port", value = "端口", required = true, dataTypeClass = Integer.class)}))
@DynamicParameter(name = "serverIp",value = "服务Ip",required = true,dataTypeClass = String.class),
@DynamicParameter(name = "port",value = "端口",required = true,dataTypeClass = Integer.class)
}))
public BaseResult addServer(@RequestBody JSONObject jsonObject) { public BaseResult addServer(@RequestBody JSONObject jsonObject) {
String serverIp = jsonObject.getString("serverIp"); String serverIp = jsonObject.getString("serverIp");
int port = jsonObject.getIntValue("port"); int port = jsonObject.getIntValue("port");
boolean res = serverService.addServer(serverIp,port); boolean res = serverService.addServer(serverIp, port);
if (res) { if (res) {
return BaseResult.success(); return BaseResult.success();
} else { } else {
...@@ -154,6 +163,7 @@ public class OperateController { ...@@ -154,6 +163,7 @@ public class OperateController {
/** /**
* 删除server * 删除server
*
* @param serverIp * @param serverIp
* @return * @return
*/ */
...@@ -161,6 +171,7 @@ public class OperateController { ...@@ -161,6 +171,7 @@ public class OperateController {
@ApiOperation(value = "删除服务接口", notes = "删除服务") @ApiOperation(value = "删除服务接口", notes = "删除服务")
@PostMapping("server/delete") @PostMapping("server/delete")
public BaseResult deleteServer(@RequestParam("serverIp") String serverIp) { public BaseResult deleteServer(@RequestParam("serverIp") String serverIp) {
serverIp = XssUtil.checkXSS(serverIp);
boolean res = serverService.deleteServer(serverIp); boolean res = serverService.deleteServer(serverIp);
if (res) { if (res) {
return BaseResult.success(); return BaseResult.success();
...@@ -171,20 +182,18 @@ public class OperateController { ...@@ -171,20 +182,18 @@ public class OperateController {
/** /**
* 修改server * 修改server
*
* @param jsonObject * @param jsonObject
* @return * @return
*/ */
@ApiOperation(value = "修改服务接口", notes = "修改服务") @ApiOperation(value = "修改服务接口", notes = "修改服务")
@PostMapping("server/update") @PostMapping("server/update")
@MyLog(title = "修改服务", optParam = "#{serverIp},#{port}", businessType = BusinessType.UPDATE) @MyLog(title = "修改服务", optParam = "#{serverIp},#{port}", businessType = BusinessType.UPDATE)
@ApiOperationSupport(params = @DynamicParameters(name = "jsonObject",properties = { @ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = {@DynamicParameter(name = "serverIp", value = "服务Ip", required = true, dataTypeClass = String.class), @DynamicParameter(name = "port", value = "端口", required = true, dataTypeClass = Integer.class)}))
@DynamicParameter(name = "serverIp",value = "服务Ip",required = true,dataTypeClass = String.class),
@DynamicParameter(name = "port",value = "端口",required = true,dataTypeClass = Integer.class)
}))
public BaseResult updateServer(@RequestBody JSONObject jsonObject) { public BaseResult updateServer(@RequestBody JSONObject jsonObject) {
String serverIp = jsonObject.getString("serverIp"); String serverIp = jsonObject.getString("serverIp");
int port = jsonObject.getInteger("port"); int port = jsonObject.getInteger("port");
boolean res = serverService.updateServer(serverIp,port); boolean res = serverService.updateServer(serverIp, port);
if (res) { if (res) {
return BaseResult.success(); return BaseResult.success();
} else { } else {
...@@ -195,6 +204,7 @@ public class OperateController { ...@@ -195,6 +204,7 @@ public class OperateController {
/** /**
* 分页查询所有的server * 分页查询所有的server
*
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @return * @return
...@@ -202,13 +212,9 @@ public class OperateController { ...@@ -202,13 +212,9 @@ public class OperateController {
@ApiOperation(value = "获取服务列表接口", notes = "用于获取服务列表") @ApiOperation(value = "获取服务列表接口", notes = "用于获取服务列表")
@GetMapping("server/list") @GetMapping("server/list")
@MyLog(title = "获取服务列表", optParam = "#{pageNo},#{pageSize}", businessType = BusinessType.SELECT) @MyLog(title = "获取服务列表", optParam = "#{pageNo},#{pageSize}", businessType = BusinessType.SELECT)
@ApiImplicitParams({ @ApiImplicitParams({@ApiImplicitParam(name = "pageNo", value = "当前在第几页", required = true, dataType = "int"), @ApiImplicitParam(name = "pageSize", value = "每页显示多少条", required = true, dataType = "int")})
@ApiImplicitParam(name = "pageNo",value = "当前在第几页", required = true,dataType = "int"), public ResResult<List<Server>> getServerList(@RequestParam("pageNo") int pageNo, @RequestParam("pageSize") int pageSize) {
@ApiImplicitParam(name = "pageSize",value = "每页显示多少条", required = true, dataType = "int") List<Server> records = serverService.getServerList(pageNo, pageSize);
}) return ResResult.success().goRecord(records);
public ResResult<List<Server>> getServerList(@RequestParam("pageNo") int pageNo,
@RequestParam("pageSize") int pageSize) {
List<Server> records = serverService.getServerList(pageNo,pageSize);
return ResResult.success().record(records);
} }
} }
...@@ -32,5 +32,4 @@ public class ResourceContrller { ...@@ -32,5 +32,4 @@ public class ResourceContrller {
public void downloadWorkHourRecordTemplate(HttpServletResponse response, @RequestParam(value = "userId") int userId) { public void downloadWorkHourRecordTemplate(HttpServletResponse response, @RequestParam(value = "userId") int userId) {
resourceManager.downloadDeviceInfoExcle(response, userId); resourceManager.downloadDeviceInfoExcle(response, userId);
} }
} }
...@@ -4,22 +4,18 @@ import io.swagger.annotations.Api; ...@@ -4,22 +4,18 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import iot.sixiang.license.entity.SysOperLog;
import iot.sixiang.license.log.BusinessType; import iot.sixiang.license.log.BusinessType;
import iot.sixiang.license.log.MyLog; import iot.sixiang.license.log.MyLog;
import iot.sixiang.license.model.PageInfoModel; import iot.sixiang.license.model.PageInfoModel;
import iot.sixiang.license.model.PageResult; import iot.sixiang.license.model.PageResult;
import iot.sixiang.license.model.vo.SysOperLogVo;
import iot.sixiang.license.service.SysOperLogService; import iot.sixiang.license.service.SysOperLogService;
import iot.sixiang.license.util.CommonUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.text.ParseException;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
...@@ -35,7 +31,6 @@ public class SysOperLogController { ...@@ -35,7 +31,6 @@ public class SysOperLogController {
/** /**
* 分页查询所有的oper_log * 分页查询所有的oper_log
*
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @return * @return
...@@ -44,28 +39,19 @@ public class SysOperLogController { ...@@ -44,28 +39,19 @@ public class SysOperLogController {
@GetMapping("operate/list") @GetMapping("operate/list")
@MyLog(title = "获取日志列表", businessType = BusinessType.SELECT) @MyLog(title = "获取日志列表", businessType = BusinessType.SELECT)
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "pageNo", value = "当前在第几页", required = true, dataType = "int"), @ApiImplicitParam(name = "pageNo",value = "当前在第几页", required = true,dataType = "int"),
@ApiImplicitParam(name = "pageSize", value = "每页显示多少条", required = true, dataType = "int"), @ApiImplicitParam(name = "pageSize",value = "每页显示多少条", required = true, dataType = "int")
@ApiImplicitParam(name = "startTime", value = "开始时间"),
@ApiImplicitParam(name = "endTime", value = "结束时间")
}) })
public PageResult<SysOperLog> getOperLogList(@RequestParam(value = "pageNo", defaultValue = "0") int pageNo, public PageResult<SysOperLogVo> getOperLogList(@RequestParam(value = "pageNo", defaultValue = "0") int pageNo,
@RequestParam(value = "pageSize", defaultValue = "0") int pageSize, @RequestParam(value = "pageSize",defaultValue = "0") int pageSize) {
@RequestParam(value = "startTime", required = false, defaultValue = "") String startTime, PageInfoModel<SysOperLogVo> records = sysOperLogService.getOperLogList(pageNo,pageSize);
@RequestParam(value = "endTime", required = false, defaultValue = "") String endTime) throws ParseException {
if (StringUtils.isEmpty(endTime)) {
endTime = CommonUtil.getDayByNum(1, CommonUtil.dateToString(new Date(), "yyyy-MM-dd"));
} else {
endTime = CommonUtil.getDayByNum(1, endTime);
}
PageInfoModel<SysOperLog> records = sysOperLogService.getOperLogList(pageNo, pageSize, startTime, endTime);
int total = records.getTotal(); int total = records.getTotal();
int pages = total / pageSize;//pages为总页数 int pages = total/pageSize;//pages为总页数
int mod = total % pageSize; int mod = total%pageSize;
if (mod != 0) { if(mod!=0){
pages = pages + 1; pages = pages +1;
} }
List<SysOperLog> result = records.getResult(); List<SysOperLogVo> result = records.getResult();
return new PageResult(200, "查找成功", pageNo, pages, total, result); return new PageResult(200, "查找成功", pageNo, pages, total, result);
} }
} }
package iot.sixiang.license.controller; package iot.sixiang.license.controller;
import com.acc.secret.util.RSAUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.DynamicParameter; import com.github.xiaoymin.knife4j.annotations.DynamicParameter;
...@@ -9,16 +10,23 @@ import io.swagger.annotations.Api; ...@@ -9,16 +10,23 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import iot.sixiang.license.entity.User;
import iot.sixiang.license.jwt.UserUtils;
import iot.sixiang.license.log.BusinessType; import iot.sixiang.license.log.BusinessType;
import iot.sixiang.license.log.MyLog; import iot.sixiang.license.log.MyLog;
import iot.sixiang.license.model.BaseResult; import iot.sixiang.license.model.BaseResult;
import iot.sixiang.license.model.PageInfoModel; import iot.sixiang.license.model.PageInfoModel;
import iot.sixiang.license.model.PageResult; import iot.sixiang.license.model.PageResult;
import iot.sixiang.license.model.dto.UpdateNotifyDTO; import iot.sixiang.license.model.vo.UserUpdatePwdVo;
import iot.sixiang.license.model.vo.UserVo; import iot.sixiang.license.model.vo.UserVo;
import iot.sixiang.license.service.UserService; import iot.sixiang.license.service.UserService;
import iot.sixiang.license.util.CommonUtil; import iot.sixiang.license.util.CommonUtil;
import iot.sixiang.license.xss.XssUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
...@@ -38,6 +46,20 @@ public class UserController { ...@@ -38,6 +46,20 @@ public class UserController {
@Autowired @Autowired
private UserService userService; private UserService userService;
@Value("${rsa.private_key}")
private String PRIVATE_KRY;
@Value("${other.error_count.change_pwd}")
private Integer changePwdMaxErrCount;
@Value("${spring.mail.to}")
private String account;
private static final String OPERATION_CHANGE = "change";
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields(new String[]{"adminCome"});
}
/** /**
* 添加user * 添加user
...@@ -74,6 +96,8 @@ public class UserController { ...@@ -74,6 +96,8 @@ public class UserController {
@PostMapping("delete") @PostMapping("delete")
@MyLog(title = "删除用户", optParam = "#{userId}", businessType = BusinessType.DELETE) @MyLog(title = "删除用户", optParam = "#{userId}", businessType = BusinessType.DELETE)
public BaseResult deleteUser(@RequestParam("userId") int userId) { public BaseResult deleteUser(@RequestParam("userId") int userId) {
userId = Integer.valueOf(XssUtil.checkXSS(String.valueOf(userId)));
boolean res = userService.deleteUser(userId); boolean res = userService.deleteUser(userId);
if (res) { if (res) {
return BaseResult.success(); return BaseResult.success();
...@@ -82,28 +106,94 @@ public class UserController { ...@@ -82,28 +106,94 @@ public class UserController {
} }
} }
/** ///**
* 修改user // * 修改user
* // *
* @param jsonObject // * @param jsonObject
* @return // * @return
*/ // */
@ApiOperation(value = "用户修改接口", notes = "修改用户") //@ApiOperation(value = "用户修改接口", notes = "修改用户")
@PostMapping("update") //@PostMapping("update")
@MyLog(title = "修改用户", optParam = "#{userId},#{password}", businessType = BusinessType.UPDATE) //@MyLog(title = "修改用户", optParam = "#{userId},#{password}", businessType = BusinessType.UPDATE)
@ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = { //@ApiOperationSupport(params = @DynamicParameters(name = "jsonObject", properties = {
@DynamicParameter(name = "userId", value = "用户Id", required = true, dataTypeClass = Integer.class), // @DynamicParameter(name = "userId", value = "用户Id", required = true, dataTypeClass = Integer.class),
@DynamicParameter(name = "password", value = "密码", required = true, dataTypeClass = String.class) // @DynamicParameter(name = "password", value = "密码", required = true, dataTypeClass = String.class)
})) //}))
public BaseResult updateUser(@RequestBody JSONObject jsonObject) { //public BaseResult updateUser(@RequestBody JSONObject jsonObject) {
int userId = jsonObject.getInteger("userId"); // int userId = jsonObject.getInteger("userId");
String password = jsonObject.getString("password"); // String password = jsonObject.getString("password");
boolean res = userService.updateUser(userId, password); // boolean res = userService.updateUser(userId, password);
if (res) { // if (res) {
return BaseResult.success(); // return BaseResult.success();
// } else {
// return BaseResult.failed();
// }
//}
@ApiOperation(value = "用户修改密码", notes = "修改密码")
@PostMapping("update_pwd")
@MyLog(title = "修改密码", businessType = BusinessType.UPDATE)
public BaseResult updatePwd(@RequestBody UserUpdatePwdVo userUpdatePwdVo) {
String errCntTimeMap = UserUtils.getErrCntTimeMap(account + OPERATION_CHANGE);
if (!StringUtils.isEmpty(errCntTimeMap)) {
if (errCntTimeMap.equals(CommonUtil.getCurDateStr())) {
return BaseResult.failed().setMsgValue("今日尝试修改密码次数已达" + changePwdMaxErrCount + "次,请明日再试");
} else {
UserUtils.removeErrCntTimeMap(account + OPERATION_CHANGE);
UserUtils.removeErrCnt(account + OPERATION_CHANGE);
}
}
String oldPassWord = userUpdatePwdVo.getOldPassWord();
String newPassWord = userUpdatePwdVo.getNewPassWord();
String userId = UserUtils.getLoginUserId();
User user;
if (!StringUtils.isEmpty(userId)) {
user = userService.getUserById(Integer.parseInt(userId));
} else { } else {
return BaseResult.failed(); return BaseResult.failed();
} }
oldPassWord = RSAUtil.getDecryptString(oldPassWord, PRIVATE_KRY);
newPassWord = RSAUtil.getDecryptString(newPassWord, PRIVATE_KRY);
Integer errCnt = UserUtils.getErrCnt(account + OPERATION_CHANGE);
if (errCnt == null) {
errCnt = 0;
}
if (oldPassWord.equals(user.getPassword())) {
if (newPassWord.length() < 8) {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码不得小于8位");
}
if (CommonUtil.verifyPasswordContainAccount(newPassWord, user.getUserName())) {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码中不得包含用户名的完整字符串、大小写变位或形似变换的字符串");
}
if (CommonUtil.isKeyBoardContinuousChar(newPassWord)) {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码不得包含键盘连续字符4个及以上");
}
if (!CommonUtil.checkPassword(newPassWord)) {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("至少由大写字母、小写字母、数字与特殊符号等4类中3类混合");
}
user.setPassword(newPassWord);
boolean b = userService.updateUser(user);
if (b) {
return BaseResult.success().setMsgValue("密码修改成功");
} else {
return BaseResult.failed().setMsgValue("密码修改失败");
}
} else {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("原密码出错");
}
}
private void computeChangePwdErrCnt(int errCnt) {
if (errCnt < changePwdMaxErrCount - 1) {
UserUtils.setErrCnt(account + OPERATION_CHANGE, errCnt + 1);
} else {
UserUtils.setErrCntTimeMap(account + OPERATION_CHANGE, CommonUtil.getCurDateStr());
}
} }
...@@ -127,6 +217,8 @@ public class UserController { ...@@ -127,6 +217,8 @@ public class UserController {
@RequestParam(value = "pageSize", defaultValue = "0") int pageSize, @RequestParam(value = "pageSize", defaultValue = "0") int pageSize,
@RequestParam(value = "userName", required = false) String userName, @RequestParam(value = "userName", required = false) String userName,
@RequestParam(value = "company", required = false) String company) { @RequestParam(value = "company", required = false) String company) {
userName = XssUtil.checkXSS(userName);
company = XssUtil.checkXSS(company);
PageInfoModel<UserVo> records = userService.getUserList(pageNo, pageSize, userName, company); PageInfoModel<UserVo> records = userService.getUserList(pageNo, pageSize, userName, company);
int total = records.getTotal(); int total = records.getTotal();
int pages = total / pageSize;//pages为总页数 int pages = total / pageSize;//pages为总页数
...@@ -135,13 +227,11 @@ public class UserController { ...@@ -135,13 +227,11 @@ public class UserController {
pages = pages + 1; pages = pages + 1;
} }
List<UserVo> result = records.getResult(); List<UserVo> result = records.getResult();
return new PageResult(200, "查找成功", pageNo, pages, total, result); String str = "uBtWZTiPMYkQLsp7rNly3RUIXKGqFbjnSg56H8ve49AC0mfO";
for (UserVo u : result) {
u.setPassword(DigestUtils.md5DigestAsHex((str + u.getPassword()).getBytes()));
} }
return new PageResult(200, "查找成功", pageNo, pages, total, result);
@ApiOperation(value = "修改通知人接口", notes = "修改通知人邮箱")
@PostMapping("update_notify")
public BaseResult updateNotify(@RequestBody UpdateNotifyDTO updateNotifyDTO) {
return userService.updateNotify(updateNotifyDTO);
} }
} }
package iot.sixiang.license.device;
import iot.sixiang.license.net.TcpServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* Title: AsyncTcpServer
* Description: TODO
*
* @author tianlai3
* @date 2022-07-16 20:30:51
*/
@Component
@Slf4j
public class AsyncTcpServer {
@Async("taskExecutor")
public void start(int port, DeviceChannelInitializer channelInitializer) {
TcpServer server = new TcpServer(port, channelInitializer);
server.start();
}
}
...@@ -22,12 +22,10 @@ public class DeviceChannelInitializer extends BaseChannelInitializer { ...@@ -22,12 +22,10 @@ public class DeviceChannelInitializer extends BaseChannelInitializer {
@Override @Override
protected void initChannel(SocketChannel ch) throws Exception { protected void initChannel(SocketChannel ch) throws Exception {
// 服务端心跳检测 // 服务端心跳检测
ch.pipeline().addLast(new IdleStateHandler(3, 0, 0, TimeUnit.SECONDS)); ch.pipeline().addLast(new IdleStateHandler(3, 0, 0, TimeUnit.SECONDS));
ch.pipeline().addLast("decoder", new DeviceDecoder()); ch.pipeline().addLast("decoder", new DeviceDecoder());
ch.pipeline().addLast("encoder", new DeviceEncoder()); ch.pipeline().addLast("encoder", new DeviceEncoder());
ch.pipeline().addLast(workGroup, "handler", handler); ch.pipeline().addLast(workGroup, "handler", handler);
} }
} }
...@@ -5,7 +5,6 @@ import iot.sixiang.license.model.PageInfoModel; ...@@ -5,7 +5,6 @@ import iot.sixiang.license.model.PageInfoModel;
import iot.sixiang.license.model.SessionContext; import iot.sixiang.license.model.SessionContext;
import iot.sixiang.license.model.vo.DeviceDetailVo; import iot.sixiang.license.model.vo.DeviceDetailVo;
import iot.sixiang.license.model.vo.DeviceVo; import iot.sixiang.license.model.vo.DeviceVo;
import iot.sixiang.license.net.TcpServer;
import iot.sixiang.license.service.DeviceService; import iot.sixiang.license.service.DeviceService;
import iot.sixiang.license.util.CommonUtil; import iot.sixiang.license.util.CommonUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -25,17 +24,19 @@ import java.util.Map; ...@@ -25,17 +24,19 @@ import java.util.Map;
public class DeviceManager { public class DeviceManager {
private Map<String, SessionContext> sessionContexts = null; private Map<String, SessionContext> sessionContexts = null;
private DeviceChannelInitializer channelInitializer; private DeviceChannelInitializer channelInitializer;
private TcpServer server = null; // private TcpServer server = null;
private int port = 18889; private int port = 18889;
private Map<String, DeviceVo> allDevice = null; private Map<String, DeviceVo> allDevice = null;
@Autowired @Autowired
private DeviceService deviceService; private DeviceService deviceService;
@Autowired @Autowired
private DeviceServerHandler handler; private DeviceServerHandler handler;
@Autowired
private AsyncTcpServer asyncTcpServer;
public DeviceManager() { public DeviceManager() {
sessionContexts = new HashMap<String, SessionContext>(); sessionContexts = new HashMap<>();
allDevice = new HashMap<String, DeviceVo>(); allDevice = new HashMap<>();
} }
@PostConstruct @PostConstruct
...@@ -44,11 +45,11 @@ public class DeviceManager { ...@@ -44,11 +45,11 @@ public class DeviceManager {
initDevices(); initDevices();
} }
private void startTcpService() { private void startTcpService() {
sessionContexts = new HashMap<String, SessionContext>(); sessionContexts = new HashMap<>();
channelInitializer = new DeviceChannelInitializer(handler); channelInitializer = new DeviceChannelInitializer(handler);
server = new TcpServer(port, channelInitializer); asyncTcpServer.start(port, channelInitializer);
server.start();
} }
public void initDevices() { public void initDevices() {
...@@ -134,7 +135,6 @@ public class DeviceManager { ...@@ -134,7 +135,6 @@ public class DeviceManager {
} }
public boolean changeSessionOffline(String channelId) { public boolean changeSessionOffline(String channelId) {
Iterator<Map.Entry<String, SessionContext>> it = sessionContexts.entrySet().iterator(); Iterator<Map.Entry<String, SessionContext>> it = sessionContexts.entrySet().iterator();
while (it.hasNext()) { while (it.hasNext()) {
Map.Entry<String, SessionContext> entry = it.next(); Map.Entry<String, SessionContext> entry = it.next();
...@@ -156,7 +156,6 @@ public class DeviceManager { ...@@ -156,7 +156,6 @@ public class DeviceManager {
PageInfoModel<DeviceDetailVo> detailVoPageInfoModel = new PageInfoModel<>(); PageInfoModel<DeviceDetailVo> detailVoPageInfoModel = new PageInfoModel<>();
List<DeviceDetailVo> detailVos = new ArrayList<>(); List<DeviceDetailVo> detailVos = new ArrayList<>();
for (DeviceVo vo : deviceVos) { for (DeviceVo vo : deviceVos) {
DeviceDetailVo detailVo = new DeviceDetailVo(); DeviceDetailVo detailVo = new DeviceDetailVo();
detailVo.setDeviceId(vo.getDeviceId()); detailVo.setDeviceId(vo.getDeviceId());
detailVo.setAppName(vo.getAppName()); detailVo.setAppName(vo.getAppName());
...@@ -173,8 +172,6 @@ public class DeviceManager { ...@@ -173,8 +172,6 @@ public class DeviceManager {
detailVo.setCurStatus(status); detailVo.setCurStatus(status);
detailVo.setOnline(online); detailVo.setOnline(online);
detailVo.setOffline(offline); detailVo.setOffline(offline);
} }
detailVos.add(detailVo); detailVos.add(detailVo);
} }
......
...@@ -14,11 +14,11 @@ import iot.sixiang.license.event.DeviceClientInactiveEvent; ...@@ -14,11 +14,11 @@ import iot.sixiang.license.event.DeviceClientInactiveEvent;
import iot.sixiang.license.event.DeviceClientLicenseEvent; import iot.sixiang.license.event.DeviceClientLicenseEvent;
import iot.sixiang.license.event.EventPublisher; import iot.sixiang.license.event.EventPublisher;
import iot.sixiang.license.event.ForwardClientRequestEvent; import iot.sixiang.license.event.ForwardClientRequestEvent;
import iot.sixiang.license.idreader.Safety;
import iot.sixiang.license.model.SessionContext; import iot.sixiang.license.model.SessionContext;
import iot.sixiang.license.model.dto.ReportErrorMsgDTO; import iot.sixiang.license.model.dto.ReportErrorMsgDTO;
import iot.sixiang.license.service.PmsUseService; import iot.sixiang.license.service.PmsUseService;
import iot.sixiang.license.service.TerminalDeviceService; import iot.sixiang.license.service.TerminalDeviceService;
import iot.sixiang.license.third_lib.LibHelper;
import iot.sixiang.license.util.CommonUtil; import iot.sixiang.license.util.CommonUtil;
import iot.sixiang.license.util.HexUtil; import iot.sixiang.license.util.HexUtil;
import iot.sixiang.license.util.SpringUtil; import iot.sixiang.license.util.SpringUtil;
...@@ -37,8 +37,6 @@ public class DeviceServerHandler extends SimpleChannelInboundHandler<Object> { ...@@ -37,8 +37,6 @@ public class DeviceServerHandler extends SimpleChannelInboundHandler<Object> {
@Autowired @Autowired
EventPublisher eventPublisher; EventPublisher eventPublisher;
@Autowired
Safety safety;
@Resource @Resource
private PmsUseService pmsUseService; private PmsUseService pmsUseService;
@Resource @Resource
...@@ -87,8 +85,9 @@ public class DeviceServerHandler extends SimpleChannelInboundHandler<Object> { ...@@ -87,8 +85,9 @@ public class DeviceServerHandler extends SimpleChannelInboundHandler<Object> {
@Override @Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception { public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
super.channelRegistered(ctx); super.channelRegistered(ctx);
log.info("设备服务器,channelRegistered:{}", ctx.channel().id().asLongText()); log.debug("设备服务器,channelRegistered:{}", ctx.channel().id().asLongText());
} }
@Override @Override
...@@ -125,7 +124,8 @@ public class DeviceServerHandler extends SimpleChannelInboundHandler<Object> { ...@@ -125,7 +124,8 @@ public class DeviceServerHandler extends SimpleChannelInboundHandler<Object> {
private boolean handleCheckAuth(SocketChannel channel, String remoteIp, int remotePort, DeviceProtocol protocol) { private boolean handleCheckAuth(SocketChannel channel, String remoteIp, int remotePort, DeviceProtocol protocol) {
// 正式代码要放开 // 正式代码要放开
byte[] bytes = safety.decodeExtendedPayload(protocol.getContent(), 0, protocol.getContent().length); LibHelper libHelper = SpringUtil.getBean(LibHelper.class);
byte[] bytes = libHelper.decodeExtendedPayload(protocol.getContent(), 0, protocol.getContent().length);
if (bytes == null) { if (bytes == null) {
return false; return false;
} }
......
...@@ -35,7 +35,7 @@ public class SysOperLog implements Serializable { ...@@ -35,7 +35,7 @@ public class SysOperLog implements Serializable {
@ApiModelProperty("参数") @ApiModelProperty("参数")
private String optParam; private String optParam;
@ApiModelProperty("业务类型(0其它 1新增 2修改 3删除)") @ApiModelProperty("业务类型(0其它 1查找 2新增 3修改 4删除)")
private Integer businessType; private Integer businessType;
@ApiModelProperty("路径名称") @ApiModelProperty("路径名称")
...@@ -49,6 +49,4 @@ public class SysOperLog implements Serializable { ...@@ -49,6 +49,4 @@ public class SysOperLog implements Serializable {
@ApiModelProperty("操作时间") @ApiModelProperty("操作时间")
private Date operTime; private Date operTime;
} }
...@@ -18,7 +18,6 @@ public class CreateForwardClientEventHandler { ...@@ -18,7 +18,6 @@ public class CreateForwardClientEventHandler {
@Autowired @Autowired
BalanceManager balanceManager; BalanceManager balanceManager;
public CreateForwardClientEventHandler() { public CreateForwardClientEventHandler() {
} }
......
package iot.sixiang.license.event; package iot.sixiang.license.event;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@Slf4j @Slf4j
public class EventPublisher { public class EventPublisher {
@Autowired @Autowired
private ApplicationEventPublisher applicationEventPublisher; private ApplicationEventPublisher applicationEventPublisher;
......
...@@ -22,7 +22,6 @@ public class ForwardClientRequestEventHandler { ...@@ -22,7 +22,6 @@ public class ForwardClientRequestEventHandler {
public ForwardClientRequestEventHandler() { public ForwardClientRequestEventHandler() {
} }
@EventListener @EventListener
......
...@@ -58,7 +58,7 @@ public class OperateSAMStatusResponseEventHandler { ...@@ -58,7 +58,7 @@ public class OperateSAMStatusResponseEventHandler {
samMonitor.setOnlineCount(onlineCount); samMonitor.setOnlineCount(onlineCount);
samMonitor.setSamCount(samCount); samMonitor.setSamCount(samCount);
operateManager.putSamMonitorMap(serverIp, samMonitor); operateManager.putSamMonitorMap(serverIp, samMonitor);
if (onlineCount / samCount > 0.7) { if ((float)onlineCount / samCount > 0.7) {
int typeId = 3; int typeId = 3;
String title = "SAM不足"; String title = "SAM不足";
String content = "当前在线客户端已超过70%"; String content = "当前在线客户端已超过70%";
......
package iot.sixiang.license.forward; package iot.sixiang.license.forward;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import iot.sixiang.license.device.DeviceManager; import iot.sixiang.license.device.DeviceManager;
import iot.sixiang.license.net.TcpClient; import iot.sixiang.license.net.TcpClient;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
@Component @Component
...@@ -13,6 +19,7 @@ import javax.annotation.Resource; ...@@ -13,6 +19,7 @@ import javax.annotation.Resource;
public class ForwardClient { public class ForwardClient {
private TcpClient client = null; private TcpClient client = null;
private ForwardChannelInitializer channelInitializer; private ForwardChannelInitializer channelInitializer;
private Bootstrap bootstrap;
@Autowired @Autowired
ForwardClientHandler handler; ForwardClientHandler handler;
...@@ -22,6 +29,22 @@ public class ForwardClient { ...@@ -22,6 +29,22 @@ public class ForwardClient {
public ForwardClient() { public ForwardClient() {
} }
@PostConstruct
public void init() {
channelInitializer = new ForwardChannelInitializer(handler);
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
bootstrap = new Bootstrap();
try {
bootstrap
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.group(eventLoopGroup)
.handler(channelInitializer);
} catch (IllegalStateException ex) {
log.error(ex.getMessage());
}
}
public void startTcp(String host, int port, String sn) { public void startTcp(String host, int port, String sn) {
log.debug("桥接客户端,开始连接桥接服务:{},{},{}", host, port, sn); log.debug("桥接客户端,开始连接桥接服务:{},{},{}", host, port, sn);
ForwardConnectionListener listener = new ForwardConnectionListener(); ForwardConnectionListener listener = new ForwardConnectionListener();
...@@ -31,7 +54,7 @@ public class ForwardClient { ...@@ -31,7 +54,7 @@ public class ForwardClient {
listener.setDeviceManager(this.deviceManager); listener.setDeviceManager(this.deviceManager);
channelInitializer = new ForwardChannelInitializer(handler); channelInitializer = new ForwardChannelInitializer(handler);
client = new TcpClient(host, port, channelInitializer, listener); client = new TcpClient(host, port, channelInitializer, listener, bootstrap);
client.start(); client.start();
} }
} }
...@@ -32,9 +32,6 @@ public class ForwardClientHandler extends SimpleChannelInboundHandler<Object> { ...@@ -32,9 +32,6 @@ public class ForwardClientHandler extends SimpleChannelInboundHandler<Object> {
// 中转客户端收到消息后,将消息原封不动的发送给设备客户端 // 中转客户端收到消息后,将消息原封不动的发送给设备客户端
log.info("read message..."); log.info("read message...");
SocketChannel channel = (SocketChannel) ctx.channel(); SocketChannel channel = (SocketChannel) ctx.channel();
//InetSocketAddress socketAddr = (InetSocketAddress) ctx.channel().remoteAddress();
//String serverIp = socketAddr.getHostString();
//int serverPort = socketAddr.getPort();
DeviceProtocol protocol = (DeviceProtocol) msg; DeviceProtocol protocol = (DeviceProtocol) msg;
String channelId = channel.id().asLongText(); String channelId = channel.id().asLongText();
......
...@@ -17,7 +17,7 @@ public class GlobalExceptionHandler { ...@@ -17,7 +17,7 @@ public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
@ResponseBody //为了返回数据 @ResponseBody //为了返回数据
public BaseResult error(Exception e){ public BaseResult error(Exception e){
log.error("出现自定义异常,{}", e.getMessage()); log.error("出现自定义异常", e);
return BaseResult.serverException(); return BaseResult.serverException();
} }
...@@ -25,7 +25,7 @@ public class GlobalExceptionHandler { ...@@ -25,7 +25,7 @@ public class GlobalExceptionHandler {
@ExceptionHandler(IotLicenseException.class) @ExceptionHandler(IotLicenseException.class)
@ResponseBody//为了返回数据 @ResponseBody//为了返回数据
public BaseResult error(IotLicenseException e){ public BaseResult error(IotLicenseException e){
log.error("出现自定义异常,{}", e.getMsg()); log.error("出现自定义异常,{}" + e.getMsg());
return BaseResult.failed().msg(e.getMsg()).code(e.getCode()); return BaseResult.failed().setMsgValue(e.getMsg()).setCodeValue(e.getCode());
} }
} }
package iot.sixiang.license.idreader;
import iot.sixiang.license.util.CommonUtil;
import org.springframework.stereotype.Component;
@Component
public class Safety {
static {
System.load(CommonUtil.getLibFilePathByFileName("IdReaderSafetyLib"));
}
public native byte[] decodeExtendedPayload(byte[] data, int offset, int length);
}
\ No newline at end of file
...@@ -29,7 +29,6 @@ public class AuthenticationInterceptor implements HandlerInterceptor { ...@@ -29,7 +29,6 @@ public class AuthenticationInterceptor implements HandlerInterceptor {
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
response.setHeader("Set-Cookie","HttpOnly");
return true; return true;
} }
} }
\ No newline at end of file
...@@ -2,31 +2,36 @@ package iot.sixiang.license.jwt; ...@@ -2,31 +2,36 @@ package iot.sixiang.license.jwt;
import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.DecodedJWT;
import iot.sixiang.license.xss.XssUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.FilterConfig; import javax.servlet.FilterConfig;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map; import java.util.Map;
@Slf4j @Slf4j
@WebFilter(filterName = "jwtFilter", urlPatterns = "/*") @WebFilter(filterName = "jwtFilter", urlPatterns = "/*")
public class JwtFilter implements Filter { public class JwtFilter implements Filter {
private static final String url1 = "/login"; private static final String url1 = "/login";
private static final String url2 = "/resource"; private static final String url2 = "/send_code";
private static final String url3 = "/doc.html"; private static final String url3 = "/doc.html";
private static final String url4 = "/v2/api-docs"; private static final String url4 = "/v2/api-docs";
private static final String url7 = "/swagger-resources"; private static final String url7 = "/swagger-resources";
private static final String url8 = "/webjars/"; private static final String url8 = "/webjars/";
private static final String url9 = "/log/get"; private static final String url9 = "/check_code";
private static final String url10 = "/reset_pwd";
private static final String url11 = "/get_token"; private static final String url11 = "/get_token";
private static final String url12 = "/report_error_msg"; private static final String url12 = "/report_error_msg";
private static final String url13 = "/bind"; private static final String url13 = "/bind";
...@@ -41,10 +46,13 @@ public class JwtFilter implements Filter { ...@@ -41,10 +46,13 @@ public class JwtFilter implements Filter {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest; final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse; final HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Set-Cookie", "cookiename=cookievalue; path=/; Domain=domainvaule; Max-age=seconds; HttpOnly");
response.setContentType("text/html; charset=utf-8"); response.setContentType("text/html; charset=utf-8");
if ("OPTIONS".equals(request.getMethod())) { if (!"GET".equals(request.getMethod()) && !"POST".equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
filterChain.doFilter(request, response); ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(new String("不安全的请求".getBytes(), StandardCharsets.UTF_8).getBytes());
outputStream.flush();
return; return;
} }
...@@ -52,8 +60,9 @@ public class JwtFilter implements Filter { ...@@ -52,8 +60,9 @@ public class JwtFilter implements Filter {
boolean check = true; boolean check = true;
String uri = request.getRequestURI(); String uri = request.getRequestURI();
if (uri.contains(url1) || uri.contains(url2) || uri.contains(url3) || uri.contains(url4) || uri.contains(url7) || uri.contains(url8) || uri.contains(url9) || uri.contains(url11)) { if (uri.contains(url1) || uri.contains(url2) || uri.contains(url3) || uri.contains(url4) || uri.contains(url7) || uri.contains(url8) || uri.contains(url9) || uri.contains(url10) || uri.contains(url11)) {
if (uri.contains(url1) || uri.contains(url2)) { if (uri.contains(url1) || uri.contains(url2)) {
uri = XssUtil.checkXSS(uri);
UserUtils.setUri(uri); UserUtils.setUri(uri);
} }
check = false; check = false;
...@@ -63,21 +72,21 @@ public class JwtFilter implements Filter { ...@@ -63,21 +72,21 @@ public class JwtFilter implements Filter {
return; return;
} }
if (token == null) { if (StringUtils.isEmpty(token)) {
request.setAttribute("msg", "认证信息不能为空"); request.setAttribute("msg", "认证信息不能为空");
request.getRequestDispatcher("/fail").forward(request, response); request.getRequestDispatcher("/iot_license/fail").forward(request, response);
return; return;
} else { } else {
DecodedJWT jwt = JwtUtil.verifyToken(token); DecodedJWT jwt = JwtUtil.verifyToken(token);
if (jwt == null) { if (jwt == null) {
request.setAttribute("msg", "认证信息非法"); request.setAttribute("msg", "认证信息非法");
request.getRequestDispatcher("/fail").forward(request, response); request.getRequestDispatcher("/iot_license/fail").forward(request, response);
return; return;
} else { } else {
Map<String, Claim> userData = jwt.getClaims(); Map<String, Claim> userData = jwt.getClaims();
if (userData == null) { if (userData == null) {
request.setAttribute("msg", "认证信息非法"); request.setAttribute("msg", "认证信息非法");
request.getRequestDispatcher("/fail").forward(request, response); request.getRequestDispatcher("/iot_license/fail").forward(request, response);
return; return;
} }
// 终端设备放行 // 终端设备放行
...@@ -87,12 +96,25 @@ public class JwtFilter implements Filter { ...@@ -87,12 +96,25 @@ public class JwtFilter implements Filter {
} }
String userId = userData.get("userId").asString(); String userId = userData.get("userId").asString();
String userName = userData.get("userName").asString(); String userName = userData.get("userName").asString();
String password = userData.get("password").asString(); String password = "";
if (!token.equals(UserUtils.getToken(userId))) {
request.setAttribute("msg", "账户已在别处登录,请重新登录");
request.getRequestDispatcher("/iot_license/fail").forward(request, response);
return;
}
LoginUser loginUser = new LoginUser(userId, userName, password); LoginUser loginUser = new LoginUser(userId, userName, password);
Date curDate = new Date();
Date tokenExp = UserUtils.getTokenExp(userId);
if (token.equals(UserUtils.getToken(userId)) && curDate.before(tokenExp)) {
UserUtils.setLoginUser(loginUser); UserUtils.setLoginUser(loginUser);
UserUtils.setUri(uri); UserUtils.setUri(uri);
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
} else {
UserUtils.removeToken(userId);
UserUtils.removeTokenExp(userId);
request.setAttribute("msg", "token已过期");
request.getRequestDispatcher("/iot_license/fail").forward(request, response);
}
} }
} }
} }
......
...@@ -3,6 +3,7 @@ package iot.sixiang.license.jwt; ...@@ -3,6 +3,7 @@ package iot.sixiang.license.jwt;
import com.auth0.jwt.JWT; import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -15,7 +16,7 @@ public class JwtUtil { ...@@ -15,7 +16,7 @@ public class JwtUtil {
/** /**
* 秘钥 * 秘钥
*/ */
private static final String SECRET = "my_secret"; private static final String SECRET = "zIG4UAymevO6CYkDqRJuXnLWdb8c9a7xNlf51irhsSZjwtgQ";
/** /**
* 过期时间 * 过期时间
...@@ -38,8 +39,8 @@ public class JwtUtil { ...@@ -38,8 +39,8 @@ public class JwtUtil {
//可以把数据存在claim中 //可以把数据存在claim中
.withClaim("userId", user.getUserId()) .withClaim("userId", user.getUserId())
.withClaim("userName", user.getUserName()) .withClaim("userName", user.getUserName())
.withClaim("password", user.getPassword()) // .withClaim("password", user.getPassword())
.withExpiresAt(expireDate) //超时设置,设置过期的日期 // .withExpiresAt(expireDate) //超时设置,设置过期的日期
.withIssuedAt(new Date()) //签发时间 .withIssuedAt(new Date()) //签发时间
.sign(Algorithm.HMAC256(SECRET)); //SECRET加密 .sign(Algorithm.HMAC256(SECRET)); //SECRET加密
return token; return token;
...@@ -69,10 +70,16 @@ public class JwtUtil { ...@@ -69,10 +70,16 @@ public class JwtUtil {
DecodedJWT jwt = null; DecodedJWT jwt = null;
try { try {
jwt = verifier.verify(token); jwt = verifier.verify(token);
} catch ( RuntimeException e) { } catch (JWTVerificationException e) {
log.error(e.getMessage()); log.error(e.getMessage());
log.error("解析编码异常"); log.error("解析编码异常");
} }
return jwt; return jwt;
} }
public static Date getTokenExp() {
//过期时间
Date expireDate = new Date(System.currentTimeMillis() + EXPIRATION * 1000);
return expireDate;
}
} }
package iot.sixiang.license.jwt; package iot.sixiang.license.jwt;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/** /**
* 存储/获取当前线程的用户信息工具类 * 存储/获取当前线程的用户信息工具类
*/ */
public abstract class UserUtils { public abstract class UserUtils {
//线程变量,存放user实体类信息,即使是静态的与其他线程也是隔离的 static Map<String, String> tokenMap = new HashMap<>();
static Map<String, Date> tokenExpTimeMap = new HashMap<>();
static Map<String, Integer> errCntMap = new HashMap<>();
static Map<String, String> errCntTimeMap = new HashMap<>();
static Map<String, String> emailCodeMap = new HashMap<>();
static Map<String, Date> emailCodeExpTimeMap = new HashMap<>();
static Map<String, Date> countFreezeDateMap = new HashMap<>();
static Map<String, Integer> codeErrCntMap = new HashMap<>();
static Map<String, String> codeFreezeTimeMap = new HashMap<>();
/**
* 线程变量,存放user实体类信息,即使是静态的也与其他线程也是隔离的
*/
private static ThreadLocal<LoginUser> userThreadLocal = new ThreadLocal<>(); private static ThreadLocal<LoginUser> userThreadLocal = new ThreadLocal<>();
//线程变量,存放uri,即使是静态的与其他线程也是隔离的
private static ThreadLocal<String> uriThreadLocal = new ThreadLocal<>(); private static ThreadLocal<String> uriThreadLocal = new ThreadLocal<>();
//从当前线程变量中获取用户信息
public static LoginUser getLoginUser() { public static LoginUser getLoginUser() {
LoginUser user = userThreadLocal.get(); LoginUser user = userThreadLocal.get();
return user; return user;
...@@ -31,32 +46,137 @@ public abstract class UserUtils { ...@@ -31,32 +46,137 @@ public abstract class UserUtils {
return null; return null;
} }
//为当前的线程变量赋值上用户信息
public static void setLoginUser(LoginUser user) { public static void setLoginUser(LoginUser user) {
userThreadLocal.set(user); userThreadLocal.set(user);
} }
//清除userThreadLocal线程变量
public static void removeUser() { public static void removeUser() {
userThreadLocal.remove(); userThreadLocal.remove();
} }
//为当前的线程变量赋值上uri信息
public static void setUri(String uri) { public static void setUri(String uri) {
uriThreadLocal.set(uri); uriThreadLocal.set(uri);
} }
/**
* 获取当前访问方法的uri
* @return
*/
public static String getUri() { public static String getUri() {
String uri = uriThreadLocal.get(); String uri = uriThreadLocal.get();
return uri; return uri;
} }
//清除uriThreadLocal线程变量
public static void removeUri() { public static void removeUri() {
uriThreadLocal.remove(); uriThreadLocal.remove();
} }
public static void setToken(String uId, String token) {
tokenMap.put(uId, token);
}
public static String getToken(String uId) {
System.out.println("---");
String s = tokenMap.get(uId);
System.out.println(s);
return tokenMap.get(uId);
}
public static void removeToken(String uId) {
tokenMap.remove(uId);
}
public static void setTokenExp(String uId, Date tokenExpTime) {
tokenExpTimeMap.put(uId, tokenExpTime);
}
public static Date getTokenExp(String uId) {
return tokenExpTimeMap.get(uId);
}
public static void removeTokenExp(String uId) {
tokenExpTimeMap.remove(uId);
}
public static void setErrCnt(String uId, Integer count) {
errCntMap.put(uId, count);
}
public static Integer getErrCnt(String uId) {
return errCntMap.get(uId);
}
public static void removeErrCnt(String uId) {
errCntMap.remove(uId);
}
public static void setCountFreezeDate(String uId, Date freezeDate) {
countFreezeDateMap.put(uId, freezeDate);
}
public static Date getCountFreezeDate(String uId) {
return countFreezeDateMap.get(uId);
}
public static void removeCountFreezeDate(String uId) {
countFreezeDateMap.remove(uId);
}
public static void setEmailCode(String email, String code) {
emailCodeMap.put(email, code);
}
public static String getEmailCode(String email) {
return emailCodeMap.get(email);
}
public static void removeEmailCode(String email) {
emailCodeMap.remove(email);
}
public static void setEmailCodeExpTime(String email, Date expTime) {
emailCodeExpTimeMap.put(email, expTime);
}
public static Date getEmailCodeExpTime(String email) {
return emailCodeExpTimeMap.get(email);
}
public static void removeEmailCodeExpTime(String email) {
emailCodeExpTimeMap.remove(email);
}
public static void setCodeErrCntMap(String account, int count) {
codeErrCntMap.put(account, count);
}
public static Integer getCodeErrCntMap(String account) {
return codeErrCntMap.get(account);
}
public static void removeCodeErrCntMap(String account) {
codeErrCntMap.remove(account);
}
public static void setCodeFreezeTimeMap(String account, String timeStr) {
codeFreezeTimeMap.put(account, timeStr);
}
public static String getCodeFreezeTimeMap(String account) {
return codeFreezeTimeMap.get(account);
}
public static void removeCodeFreezeTimeMap(String account) {
codeFreezeTimeMap.remove(account);
}
public static void setErrCntTimeMap(String account, String timeStr) {
errCntTimeMap.put(account, timeStr);
}
public static String getErrCntTimeMap(String account) {
return errCntTimeMap.get(account);
}
public static void removeErrCntTimeMap(String account) {
errCntTimeMap.remove(account);
}
} }
...@@ -2,6 +2,7 @@ package iot.sixiang.license.mapper; ...@@ -2,6 +2,7 @@ package iot.sixiang.license.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import iot.sixiang.license.entity.SysOperLog; import iot.sixiang.license.entity.SysOperLog;
import iot.sixiang.license.model.vo.SysOperLogVo;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
...@@ -18,5 +19,5 @@ public interface SysOperLogMapper extends BaseMapper<SysOperLog> { ...@@ -18,5 +19,5 @@ public interface SysOperLogMapper extends BaseMapper<SysOperLog> {
boolean addOperlog(String title, Integer businessType, String uri, Integer status, String optParam, String errorMsg, Date operTime); boolean addOperlog(String title, Integer businessType, String uri, Integer status, String optParam, String errorMsg, Date operTime);
List<SysOperLog> getOperLogList(String startTime, String endTime); List<SysOperLogVo> getOperLogList();
} }
...@@ -26,4 +26,6 @@ public interface UserMapper extends BaseMapper<User> { ...@@ -26,4 +26,6 @@ public interface UserMapper extends BaseMapper<User> {
List<UserVo> getUserList( String userName, String company); List<UserVo> getUserList( String userName, String company);
User getUserByUserName(String userName); User getUserByUserName(String userName);
User getUserById(int userId);
} }
...@@ -69,13 +69,13 @@ public class BaseResult { ...@@ -69,13 +69,13 @@ public class BaseResult {
} }
public BaseResult code(long code) { public BaseResult setCodeValue(long code) {
this.code = code; this.code = code;
return this; return this;
} }
public BaseResult msg(String message) { public BaseResult setMsgValue(String message) {
this.msg = message; this.msg = message;
return this; return this;
} }
......
...@@ -30,60 +30,64 @@ public class ResResult<T> { ...@@ -30,60 +30,64 @@ public class ResResult<T> {
/** /**
* code = 200 * code = 200
* msg = 操作成功 * msg = 操作成功
*
* @return * @return
*/ */
public static ResResult success() { public static ResResult success() {
return new ResResult(ResultCode.SUCCESS.getCode(),ResultCode.SUCCESS.getMsg()); return new ResResult(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg());
} }
/** /**
* code = 400 * code = 400
* msg = 服务异常 * msg = 服务异常
*
* @return * @return
*/ */
public static ResResult serverException() { public static ResResult serverException() {
return new ResResult(ResultCode.SERVER_EXCEPTION.getCode(),ResultCode.SERVER_EXCEPTION.getMsg()); return new ResResult(ResultCode.SERVER_EXCEPTION.getCode(), ResultCode.SERVER_EXCEPTION.getMsg());
} }
/** /**
* code = 401 * code = 401
* msg = 暂未登录或token已经过期 * msg = 暂未登录或token已经过期
*
* @return * @return
*/ */
public static ResResult unauthorized() { public static ResResult unauthorized() {
return new ResResult(ResultCode.UNAUTHORIZED.getCode(),ResultCode.UNAUTHORIZED.getMsg()); return new ResResult(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMsg());
} }
/** /**
* code = 402 * code = 402
* msg = 参数校验失败 * msg = 参数校验失败
*
* @return * @return
*/ */
public static ResResult validate_failed() { public static ResResult validate_failed() {
return new ResResult(ResultCode.VALIDATE_FAILED.getCode(),ResultCode.VALIDATE_FAILED.getMsg()); return new ResResult(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg());
} }
/** /**
* code = 403 * code = 403
* msg = 操作失败(数据库增删改查等失败) * msg = 操作失败(数据库增删改查等失败)
*
* @return * @return
*/ */
public static ResResult failed() { public static ResResult failed() {
return new ResResult(ResultCode.FAILED.getCode(),ResultCode.FAILED.getMsg()); return new ResResult(ResultCode.FAILED.getCode(), ResultCode.FAILED.getMsg());
} }
public ResResult code(long code) { public ResResult setCodeValue(long code) {
this.code = code; this.code = code;
return this; return this;
} }
public ResResult msg(String message) { public ResResult setMsgValue(String message) {
this.msg = message; this.msg = message;
return this; return this;
} }
public ResResult record(T data){ public ResResult goRecord(T data) {
this.record = data; this.record = data;
return this; return this;
} }
......
package iot.sixiang.license.model.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* Created by m33
* Date 2022/9/23 17:46
* Description
*/
@Data
public class CheckCodeDto {
@ApiModelProperty("验证码")
private String code;
}
package iot.sixiang.license.model.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* Title: EncryptVo
* Description: TODO
*
* @author tianlai3
* @date 2022-07-13 01:10:10
*/
@Data
public class EncryptVo {
@ApiModelProperty(value = "数据")
private String message;
}
package iot.sixiang.license.model.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* Created by m33
* Date 2022/9/8 10:45
* Description
*/
@Data
public class LoginReqVo {
@ApiModelProperty("用户名")
private String userName;
@ApiModelProperty("密码")
private String password;
@ApiModelProperty("验证码")
private String code;
}
...@@ -3,6 +3,8 @@ package iot.sixiang.license.model.vo; ...@@ -3,6 +3,8 @@ package iot.sixiang.license.model.vo;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import java.util.Date;
/** /**
* Created by m33 on 2022/6/14 18:51 * Created by m33 on 2022/6/14 18:51
*/ */
...@@ -11,4 +13,7 @@ public class LoginVo { ...@@ -11,4 +13,7 @@ public class LoginVo {
@ApiModelProperty("token") @ApiModelProperty("token")
private String authorization; private String authorization;
@ApiModelProperty("更新时间")
private Date updateTime;
} }
package iot.sixiang.license.model.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* Title: MaskingVo
* Description: TODO
*
* @author tianlai3
* @date 2022-07-13 01:42:04
*/
@Data
public class MaskingVo {
@ApiModelProperty(value = "用户姓名")
private String userName;
@ApiModelProperty(value = "身份证号")
private String idCard;
}
package iot.sixiang.license.model.vo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* Created by m33
* Date 2022/9/7 14:52
* Description
*/
@Data
public class SysOperLogVo {
@ApiModelProperty("主键Id")
private Integer id;
@ApiModelProperty("模块标题")
private String title;
@ApiModelProperty("业务类型(0其它 1查找 2新增 3修改 4删除)")
private Integer businessType;
@ApiModelProperty("路径名称")
private String uri;
@ApiModelProperty("操作状态(0正常 1异常)")
private Integer status;
@ApiModelProperty("错误消息")
private String errorMsg;
@ApiModelProperty("操作时间")
private Date operTime;
}
package iot.sixiang.license.model.vo;
import lombok.Data;
/**
* Created by m33
* Date 2022/9/23 18:32
* Description
*/
@Data
public class UserResetPwdVo {
private String password;
}
package iot.sixiang.license.model.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* Created by m33
* Date 2022/9/7 15:06
* Description
*/
@Data
public class UserUpdatePwdVo {
@ApiModelProperty(value = "旧密码")
private String oldPassWord;
@ApiModelProperty(value = "新密码")
private String newPassWord;
}
...@@ -2,10 +2,6 @@ package iot.sixiang.license.net; ...@@ -2,10 +2,6 @@ package iot.sixiang.license.net;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
...@@ -14,33 +10,18 @@ public class TcpClient { ...@@ -14,33 +10,18 @@ public class TcpClient {
private String host; private String host;
private BaseChannelInitializer channelInitializer; private BaseChannelInitializer channelInitializer;
private BaseConnectionListener connectionListener; private BaseConnectionListener connectionListener;
private Bootstrap bootstrap;
public TcpClient(String host, int port, BaseChannelInitializer channelInitializer, BaseConnectionListener connectionListener) { public TcpClient(String host, int port, BaseChannelInitializer channelInitializer, BaseConnectionListener connectionListener, Bootstrap bootstrap) {
this.host = host; this.host = host;
this.port = port; this.port = port;
this.channelInitializer = channelInitializer; this.channelInitializer = channelInitializer;
this.connectionListener = connectionListener; this.connectionListener = connectionListener;
this.bootstrap = bootstrap;
} }
public void start() { public void start() {
Thread thread = new Thread(() -> {
try {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.group(eventLoopGroup)
.remoteAddress(host, port)
.handler(channelInitializer);
ChannelFuture future = bootstrap.connect(host, port); ChannelFuture future = bootstrap.connect(host, port);
future.addListener(connectionListener); future.addListener(connectionListener);
} catch (Exception e) {
e.printStackTrace();
log.error("Tcp客户端异常,端口:{}", port);
}
});
thread.start();
} }
} }
...@@ -10,7 +10,6 @@ import lombok.extern.slf4j.Slf4j; ...@@ -10,7 +10,6 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class TcpServer { public class TcpServer {
private int port; private int port;
private BaseChannelInitializer channelInitializer; private BaseChannelInitializer channelInitializer;
...@@ -20,13 +19,10 @@ public class TcpServer { ...@@ -20,13 +19,10 @@ public class TcpServer {
} }
public void start() { public void start() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//创建两个线程组 bossGroup、workerGroup //创建两个线程组 bossGroup、workerGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(4); EventLoopGroup bossGroup = new NioEventLoopGroup(4);
EventLoopGroup workerGroup = new NioEventLoopGroup(4); EventLoopGroup workerGroup = new NioEventLoopGroup(4);
log.debug("Tcp服务,开始监听端口:{}", port); log.info("Tcp服务,开始监听端口:{}", port);
//创建服务端的启动对象,设置参数 //创建服务端的启动对象,设置参数
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
//设置两个线程组boosGroup和workerGroup //设置两个线程组boosGroup和workerGroup
...@@ -44,15 +40,15 @@ public class TcpServer { ...@@ -44,15 +40,15 @@ public class TcpServer {
f = b.bind(port).sync(); f = b.bind(port).sync();
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
} catch (InterruptedException e) { } catch (InterruptedException e) {
// TODO Auto-generated catch block
log.error("Tcp服务异常,端口:{}", port); log.error("Tcp服务异常,端口:{}", port);
} finally { } finally {
log.debug("Tcp服务,停止退出"); log.info("Tcp服务,停止退出");
if (workerGroup != null) {
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
}
if (bossGroup != null) {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
} }
} }
});
thread.start();
} }
} }
package iot.sixiang.license.operate; package iot.sixiang.license.operate;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import iot.sixiang.license.net.TcpClient; import iot.sixiang.license.net.TcpClient;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component @Component
@Slf4j @Slf4j
public class OperateClient { public class OperateClient {
...@@ -12,7 +19,7 @@ public class OperateClient { ...@@ -12,7 +19,7 @@ public class OperateClient {
private TcpClient client = null; private TcpClient client = null;
private OperateChannelInitializer channelInitializer; private OperateChannelInitializer channelInitializer;
private Bootstrap bootstrap;
@Autowired @Autowired
OperateClientHandler handler; OperateClientHandler handler;
...@@ -21,13 +28,28 @@ public class OperateClient { ...@@ -21,13 +28,28 @@ public class OperateClient {
} }
@PostConstruct
public void init(){
channelInitializer = new OperateChannelInitializer(handler);
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
bootstrap = new Bootstrap();
try {
bootstrap
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.group(eventLoopGroup)
.handler(channelInitializer);
} catch (IllegalStateException ex) {
log.error(ex.getMessage());
}
}
public void startTcp(String host, int port) { public void startTcp(String host, int port) {
OperateConnectionListener listener = new OperateConnectionListener(); OperateConnectionListener listener = new OperateConnectionListener();
listener.setHost(host); listener.setHost(host);
listener.setPort(port); listener.setPort(port);
channelInitializer = new OperateChannelInitializer(handler); client = new TcpClient(host, port, channelInitializer, listener, bootstrap);
client = new TcpClient(host, port, channelInitializer, listener);
client.start(); client.start();
} }
......
...@@ -22,7 +22,7 @@ public class ResourceManager { ...@@ -22,7 +22,7 @@ public class ResourceManager {
@Autowired @Autowired
ResourceService resourceService; ResourceService resourceService;
public void downloadDeviceInfoExcle(HttpServletResponse response, int userId) throws IOException { public void downloadDeviceInfoExcle(HttpServletResponse response, int userId){
OutputStream os = null; OutputStream os = null;
HSSFWorkbook wb = null; HSSFWorkbook wb = null;
try { try {
...@@ -129,13 +129,21 @@ public class ResourceManager { ...@@ -129,13 +129,21 @@ public class ResourceManager {
} }
wb.write(os); wb.write(os);
} catch (IOException e) { } catch (IOException e) {
log.error("Excel表格信息下载异常,{}",e.getMessage()); log.error("Excel表格信息下载异常,{}", e.getMessage());
} finally { } finally {
if (os != null) { if (os != null) {
try {
os.close(); os.close();
} catch (IOException e) {
log.error("Excel表格信息下载异常,{}", e.getMessage());
}
} }
if (wb != null) { if (wb != null) {
try {
wb.close(); wb.close();
} catch (IOException e) {
log.error("Excel表格信息下载异常,{}", e.getMessage());
}
} }
} }
} }
......
...@@ -3,6 +3,7 @@ package iot.sixiang.license.service; ...@@ -3,6 +3,7 @@ package iot.sixiang.license.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import iot.sixiang.license.entity.SysOperLog; import iot.sixiang.license.entity.SysOperLog;
import iot.sixiang.license.model.PageInfoModel; import iot.sixiang.license.model.PageInfoModel;
import iot.sixiang.license.model.vo.SysOperLogVo;
import java.util.Date; import java.util.Date;
...@@ -17,5 +18,5 @@ import java.util.Date; ...@@ -17,5 +18,5 @@ import java.util.Date;
public interface SysOperLogService extends IService<SysOperLog> { public interface SysOperLogService extends IService<SysOperLog> {
boolean addOperlog(String title, Integer businessType, String uri, Integer status, String optParam, String errorMsg, Date operTime); boolean addOperlog(String title, Integer businessType, String uri, Integer status, String optParam, String errorMsg, Date operTime);
PageInfoModel<SysOperLog> getOperLogList(int pageNo, int pageSize, String startTime, String endTime); PageInfoModel<SysOperLogVo> getOperLogList(int pageNo, int pageSize);
} }
package iot.sixiang.license.service; package iot.sixiang.license.service;
import iot.sixiang.license.model.BaseResult; import iot.sixiang.license.entity.User;
import iot.sixiang.license.model.PageInfoModel; import iot.sixiang.license.model.PageInfoModel;
import iot.sixiang.license.model.dto.UpdateNotifyDTO;
import iot.sixiang.license.model.vo.UserVo; import iot.sixiang.license.model.vo.UserVo;
/** /**
...@@ -13,15 +12,17 @@ import iot.sixiang.license.model.vo.UserVo; ...@@ -13,15 +12,17 @@ import iot.sixiang.license.model.vo.UserVo;
* @author m33 * @author m33
* @since 2022-06-06 * @since 2022-06-06
*/ */
public interface UserService{ public interface UserService {
boolean deleteUser(int userIdVo); boolean deleteUser(int userIdVo);
boolean addUser(String userName, String company, String password); boolean addUser(String userName, String company, String password);
boolean updateUser(int userId, String password); boolean updateUser(User user);
PageInfoModel<UserVo> getUserList(int pageNo, int pageSize, String userName, String company); PageInfoModel<UserVo> getUserList(int pageNo, int pageSize, String userName, String company);
BaseResult updateNotify(UpdateNotifyDTO updateNotifyDTO); User getUserById(int userId);
User getUserByName(String root);
} }
...@@ -8,9 +8,14 @@ import iot.sixiang.license.mapper.AlarmMapper; ...@@ -8,9 +8,14 @@ import iot.sixiang.license.mapper.AlarmMapper;
import iot.sixiang.license.mapper.AlarmReadMapper; import iot.sixiang.license.mapper.AlarmReadMapper;
import iot.sixiang.license.model.vo.AlarmVo; import iot.sixiang.license.model.vo.AlarmVo;
import iot.sixiang.license.service.AlarmReadService; import iot.sixiang.license.service.AlarmReadService;
import iot.sixiang.license.util.CommonUtil;
import iot.sixiang.license.xss.XssUtil;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
/** /**
...@@ -29,11 +34,13 @@ public class AlarmReadServiceImpl extends ServiceImpl<AlarmReadMapper, AlarmRead ...@@ -29,11 +34,13 @@ public class AlarmReadServiceImpl extends ServiceImpl<AlarmReadMapper, AlarmRead
@Resource @Resource
AlarmReadMapper alarmReadMapper; AlarmReadMapper alarmReadMapper;
@Override @Override
public boolean readAlarm(int userId) { public boolean readAlarm(int userId) {
if (userId == 0) { if (userId == 0) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(),ResultCode.VALIDATE_FAILED.getMsg()); throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(),ResultCode.VALIDATE_FAILED.getMsg());
} }
userId = Integer.valueOf(XssUtil.checkXSS(String.valueOf(userId)));
List<AlarmVo> alarmList = alarmMapper.getAlarmList(userId); List<AlarmVo> alarmList = alarmMapper.getAlarmList(userId);
for (AlarmVo alarm: alarmList) { for (AlarmVo alarm: alarmList) {
if (alarm.getReadFlag() == 0) { if (alarm.getReadFlag() == 0) {
...@@ -41,6 +48,12 @@ public class AlarmReadServiceImpl extends ServiceImpl<AlarmReadMapper, AlarmRead ...@@ -41,6 +48,12 @@ public class AlarmReadServiceImpl extends ServiceImpl<AlarmReadMapper, AlarmRead
int typeId = alarm.getTypeId(); int typeId = alarm.getTypeId();
String title = alarm.getTitle(); String title = alarm.getTitle();
String content = alarm.getContent(); String content = alarm.getContent();
alarmId = Integer.valueOf(XssUtil.checkXSS(String.valueOf(alarmId)));
typeId = Integer.valueOf(XssUtil.checkXSS(String.valueOf(typeId)));
title = XssUtil.checkXSS(title);
content = XssUtil.checkXSS(content);
boolean res = alarmReadMapper.readAlarm(alarmId, typeId, title, content, userId); boolean res = alarmReadMapper.readAlarm(alarmId, typeId, title, content, userId);
if (!res) { if (!res) {
return false; return false;
......
...@@ -7,6 +7,8 @@ import iot.sixiang.license.handler.IotLicenseException; ...@@ -7,6 +7,8 @@ import iot.sixiang.license.handler.IotLicenseException;
import iot.sixiang.license.mapper.AlarmMapper; import iot.sixiang.license.mapper.AlarmMapper;
import iot.sixiang.license.model.vo.AlarmVo; import iot.sixiang.license.model.vo.AlarmVo;
import iot.sixiang.license.service.AlarmService; import iot.sixiang.license.service.AlarmService;
import iot.sixiang.license.util.CommonUtil;
import org.owasp.esapi.ESAPI;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
...@@ -25,12 +27,17 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements ...@@ -25,12 +27,17 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
} }
@Override @Override
public List<AlarmVo> getAlarmList(int userId) { public List<AlarmVo> getAlarmList(int uI) {
if (userId == 0) { if (uI == 0) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg()); throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg());
} }
List<AlarmVo> alarmVos = alarmMapper.getAlarmList(userId); List<AlarmVo> alarmVos = alarmMapper.getAlarmList(uI);
alarmVos = alarmVos.stream().sorted(Comparator.comparing(AlarmVo::getCreateTime, Comparator.reverseOrder())).collect(Collectors.toList()); alarmVos = alarmVos.stream().sorted(Comparator.comparing(AlarmVo::getCreateTime, Comparator.reverseOrder())).collect(Collectors.toList());
if (alarmVos != null && !alarmVos.isEmpty()) {
for (AlarmVo alarmVo : alarmVos) {
alarmVo.setContent(ESAPI.encoder().encodeForDN(alarmVo.getContent()));
}
}
return alarmVos; return alarmVos;
} }
} }
...@@ -138,7 +138,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme ...@@ -138,7 +138,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
queryWrapper.eq(Device::getSnBind, snBind).last("limit 1"); queryWrapper.eq(Device::getSnBind, snBind).last("limit 1");
Device device = deviceMapper.selectOne(queryWrapper); Device device = deviceMapper.selectOne(queryWrapper);
if (device != null) { if (device != null) {
return ResResult.success().record(device.getSn()); return ResResult.success().goRecord(device.getSn());
} else { } else {
return new ResResult(405, "未绑定"); return new ResResult(405, "未绑定");
} }
...@@ -156,7 +156,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme ...@@ -156,7 +156,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
if (deviceId.equals(device.getDeviceId())) { if (deviceId.equals(device.getDeviceId())) {
return BaseResult.success(); return BaseResult.success();
} else { } else {
return BaseResult.failed().msg("设备sn已被绑定"); return BaseResult.failed().setMsgValue("设备sn已被绑定");
} }
} }
LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
...@@ -164,10 +164,10 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme ...@@ -164,10 +164,10 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
Device tempDevice = deviceMapper.selectOne(wrapper); Device tempDevice = deviceMapper.selectOne(wrapper);
if (tempDevice != null) { if (tempDevice != null) {
if (!StringUtils.isEmpty(tempDevice.getSnBind())) { if (!StringUtils.isEmpty(tempDevice.getSnBind())) {
return BaseResult.failed().msg("设备已绑定sn"); return BaseResult.failed().setMsgValue("设备已绑定sn");
} }
} else { } else {
return BaseResult.failed().msg("请输入正确的id"); return BaseResult.failed().setMsgValue("请输入正确的id");
} }
tempDevice.setSn(sn); tempDevice.setSn(sn);
tempDevice.setSnBind(snBind); tempDevice.setSnBind(snBind);
......
...@@ -6,12 +6,13 @@ import iot.sixiang.license.entity.SysOperLog; ...@@ -6,12 +6,13 @@ import iot.sixiang.license.entity.SysOperLog;
import iot.sixiang.license.handler.IotLicenseException; import iot.sixiang.license.handler.IotLicenseException;
import iot.sixiang.license.mapper.SysOperLogMapper; import iot.sixiang.license.mapper.SysOperLogMapper;
import iot.sixiang.license.model.PageInfoModel; import iot.sixiang.license.model.PageInfoModel;
import iot.sixiang.license.model.vo.SysOperLogVo;
import iot.sixiang.license.service.SysOperLogService; import iot.sixiang.license.service.SysOperLogService;
import iot.sixiang.license.xss.XssUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -32,23 +33,29 @@ public class SysOperLogServiceImpl extends ServiceImpl<SysOperLogMapper, SysOper ...@@ -32,23 +33,29 @@ public class SysOperLogServiceImpl extends ServiceImpl<SysOperLogMapper, SysOper
@Override @Override
public boolean addOperlog(String title, Integer businessType, String uri, Integer status, String optParam, String errorMsg, Date operTime) { public boolean addOperlog(String title, Integer businessType, String uri, Integer status, String optParam, String errorMsg, Date operTime) {
title = XssUtil.checkXSS(title);
businessType = Integer.valueOf(XssUtil.checkXSS(String.valueOf(businessType)));
uri = XssUtil.checkXSS(uri);
status = Integer.valueOf(XssUtil.checkXSS(String.valueOf(status)));
optParam = XssUtil.checkXSS(optParam);
errorMsg = XssUtil.checkXSS(errorMsg);
// operTime = XssUtil.checkXSS(operTime);
return sysOperLogMapper.addOperlog(title, businessType, uri, status, optParam, errorMsg, operTime); return sysOperLogMapper.addOperlog(title, businessType, uri, status, optParam, errorMsg, operTime);
} }
@Override @Override
public PageInfoModel<SysOperLog> getOperLogList(int pageNo, int pageSize, String startTime, String endTime) { public PageInfoModel<SysOperLogVo> getOperLogList(int pageNo, int pageSize) {
if (pageNo == 0 || pageSize == 0) { if(pageNo == 0 || pageSize == 0) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg()); throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(),ResultCode.VALIDATE_FAILED.getMsg());
} }
List<SysOperLog> records = sysOperLogMapper.getOperLogList(startTime, endTime); List<SysOperLogVo> records = sysOperLogMapper.getOperLogList();
records = records.stream().sorted(Comparator.comparing(SysOperLog::getOperTime, Comparator.reverseOrder())).collect(Collectors.toList()); List<SysOperLogVo> result = new ArrayList<>();
List<SysOperLog> result = new ArrayList<>();
int begin = (pageNo - 1) * pageSize; int begin = (pageNo - 1) * pageSize;
if (begin >= 0 && records.size() > 0) { if (begin >= 0 && records.size() > 0) {
result = records.stream().skip(begin).limit(pageSize).collect(Collectors.toList()); result = records.stream().skip(begin).limit(pageSize).collect(Collectors.toList());
} }
PageInfoModel<SysOperLog> objectPageInfoModel = new PageInfoModel<>(); PageInfoModel<SysOperLogVo> objectPageInfoModel = new PageInfoModel<>();
objectPageInfoModel.setTotal(records.size()); objectPageInfoModel.setTotal(records.size());
objectPageInfoModel.setResult(result); objectPageInfoModel.setResult(result);
return objectPageInfoModel; return objectPageInfoModel;
......
...@@ -52,7 +52,7 @@ public class TerminalDeviceServiceImpl implements TerminalDeviceService { ...@@ -52,7 +52,7 @@ public class TerminalDeviceServiceImpl implements TerminalDeviceService {
user.setUserId(appId); user.setUserId(appId);
user.setUserName(sn); user.setUserName(sn);
String token = JwtUtil.createToken(user); String token = JwtUtil.createToken(user);
return ResResult.success().record(token); return ResResult.success().goRecord(token);
} else { } else {
return ResResult.validate_failed(); return ResResult.validate_failed();
} }
......
package iot.sixiang.license.service.impl; package iot.sixiang.license.service.impl;
import cn.hutool.core.lang.Validator;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import iot.sixiang.license.consts.ResultCode; import iot.sixiang.license.consts.ResultCode;
import iot.sixiang.license.entity.User; import iot.sixiang.license.entity.User;
import iot.sixiang.license.handler.IotLicenseException; import iot.sixiang.license.handler.IotLicenseException;
import iot.sixiang.license.jwt.UserUtils;
import iot.sixiang.license.mapper.UserMapper; import iot.sixiang.license.mapper.UserMapper;
import iot.sixiang.license.model.BaseResult;
import iot.sixiang.license.model.PageInfoModel; import iot.sixiang.license.model.PageInfoModel;
import iot.sixiang.license.model.dto.UpdateNotifyDTO;
import iot.sixiang.license.model.vo.UserVo; import iot.sixiang.license.model.vo.UserVo;
import iot.sixiang.license.service.UserService; import iot.sixiang.license.service.UserService;
import iot.sixiang.license.util.CommonUtil; import iot.sixiang.license.util.CommonUtil;
...@@ -21,7 +17,6 @@ import org.springframework.stereotype.Service; ...@@ -21,7 +17,6 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -58,27 +53,15 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us ...@@ -58,27 +53,15 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
} }
@Override @Override
public BaseResult updateNotify(UpdateNotifyDTO updateNotifyDTO) { public User getUserById(int userId) {
String notify = updateNotifyDTO.getNotify(); return userMapper.getUserById(userId);
String loginUserId = UserUtils.getLoginUserId();
if (StringUtils.isEmpty(notify) || !Validator.isEmail(notify)) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg());
}
if (StringUtils.isEmpty(loginUserId)) {
throw new IotLicenseException(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMsg());
} }
int userId = Integer.parseInt(loginUserId);
User user = new User(); @Override
user.setNotify(notify); public User getUserByName(String root) {
user.setUpdateTime(new Date());
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUserId, userId); wrapper.eq(User::getUserName, root).last("limit 1");
int res = userMapper.update(user, wrapper); return userMapper.selectOne(wrapper);
if (res > 0) {
return BaseResult.success();
} else {
return BaseResult.failed();
}
} }
@Override @Override
...@@ -91,25 +74,18 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us ...@@ -91,25 +74,18 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
@Override @Override
public boolean addUser(String userName, String company, String password) { public boolean addUser(String userName, String company, String password) {
String notify = null; if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(company) || !CommonUtil.regularMessage(userName)) {
if (Validator.isEmail(userName)) {
notify = userName;
}
if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(company) || (notify == null && !CommonUtil.regularMessage(userName))) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg()); throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg());
} }
User res = userMapper.getUserByUserName(userName); User res = userMapper.getUserByUserName(userName);
if (res != null) { if (res != null) {
throw new IotLicenseException(403, "用户名已存在"); throw new IotLicenseException(403, "用户名已存在");
} }
return userMapper.addUser(userName, company, password, notify); return userMapper.addUser(userName, company, password);
} }
@Override @Override
public boolean updateUser(int userId, String password) { public boolean updateUser(User user) {
if (userId == 0 || StringUtils.isEmpty(password)) { return userMapper.updateUser(user.getUserId(), user.getPassword());
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg());
}
return userMapper.updateUser(userId, password);
} }
} }
package iot.sixiang.license.third_lib;
import iot.sixiang.license.idreader.LibPathUtil;
import iot.sixiang.license.idreader.Safety;
import iot.sixiang.license.util.CommonUtil;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* Title: LibHelper
* Description: TODO
*
* @author tianlai3
* @date 2022-07-17 19:03:09
*/
@Component
public class LibHelper {
private Safety safety;
@PostConstruct
public void init() {
LibPathUtil.libDir = CommonUtil.getServerParentDirectory();
safety = new Safety();
}
public byte[] decodeExtendedPayload(byte[] data, int offset, int length) {
return safety.decodeExtendedPayload(data, offset, length);
}
}
\ No newline at end of file
package iot.sixiang.license.util;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
public class CodeGenerator {
public static void main(String[] args) {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
// String projectPath = System.getProperty("user.dir");
gc.setOutputDir("D:\\zengtianlai\\test2\\ioc_sixiang_license\\license" + "/src/main/java");
gc.setAuthor("lai");
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
gc.setServiceName("%sService"); //去掉Service接口的首字母I
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/iot_license?serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("license"); //模块名
pc.setParent("iot.sixiang");
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("sys_oper_log");
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
package iot.sixiang.license.util; package iot.sixiang.license.util;
import iot.sixiang.license.consts.Constant; import iot.sixiang.license.consts.Constant;
import iot.sixiang.license.model.ResResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.TextUtils;
import org.springframework.boot.system.ApplicationHome; import org.springframework.boot.system.ApplicationHome;
import java.io.File; import java.io.File;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j @Slf4j
public class CommonUtil { public class CommonUtil {
/** /**
* 获取指定日期前或后几天 * 验证密码-是否包含用户名字符(密码应与用户名无相关性,密码中不得包含用户名的完整字符串、大小写变位或形似变换的字符串)
*/
public static boolean verifyPasswordContainAccount(String password, String account) {
boolean isContain = false;
if (!TextUtils.isEmpty(password) && !TextUtils.isEmpty(account)) {
password = password.toLowerCase();
account = account.toLowerCase();
if (password.contains(account)) {
return true;
}
String[] likes = {"a", "l", "o"};
String[] likeSign = {"@", "!", "0"};
String originalAccount = account + "";
for (int i = 0; i < likes.length; i++) {
String tempAccount = originalAccount.replace(likes[i], likeSign[i]);
account = account.replace(likes[i], likeSign[i]);
if (password.contains(tempAccount) || password.contains(account)) {
return true;
}
}
}
return isContain;
}
/**
* 键盘连续字符统计4个
* *
* @param str
* @return * @return
*/ */
public static String getDayByNum(int num, String dateStr) throws ParseException { public static boolean isKeyBoardContinuousChar(String str) {
//获取指定当前日期的前三天时间 boolean result = false;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); char[][] c1 = {
Date date = format.parse(dateStr); {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+'},
Calendar calendar = Calendar.getInstance(); {'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', '|'},
calendar.setTime(date); {'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', '"'},
calendar.add(Calendar.DATE, num); {'z', 'x', 'c', 'v', 'b', 'n', 'm', '<', '>', '?'}
date = calendar.getTime(); };
return format.format(date); char[][] c2 = {
{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '='},
{'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', '\\'},
{'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\''},
{'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/'}
};
for (char[][] c : new char[][][]{c1, c2}) {
//横向
for (char[] chars : c) {
for (int j = 0; j < chars.length - 3; j++) {
//创建连续字符
StringBuffer sb = new StringBuffer();
for (int k = j; k < j + 4; k++) {
sb.append(chars[k]);
}
String keyStr = sb.toString();
if (str.contains(keyStr)) {
return true;
}
}
}
//纵向
for (int i = 0; i < c[3].length; i++) {
//创建连续字符--每列只有4个
StringBuffer sb = new StringBuffer();
for (int j = 0; j < 4; j++) {
sb.append(c[j][i]);
}
String keyStr = sb.toString();
if (str.contains(keyStr)) {
return true;
}
}
}
return result;
}
public static void main(String[] args) {
boolean b = checkPassword("1234qwe123");
System.out.println(b);
} }
/** /**
* date 转 字符串 * 密码验证
* @param date * (至少由8位及以上大写字母、小写字母、数字与特殊符号等4类中3类混合)
* @param pattern *
* @param password
* @return * @return
*/ */
public static String dateToString(Date date, String pattern) { public static boolean checkPassword(String password) {
SimpleDateFormat ft = new SimpleDateFormat(pattern); boolean flag = false;
return ft.format(date); try {
int c = 0;
if (find("[a-z]+", password)) {
c++;
}
if (find("[A-Z]+", password)) {
c++;
}
if (find("[0-9]+", password)) {
c++;
}
if (find("\\W+|_", password) && !find("\\s+", password)) {//特殊符号
c++;
}
if (c >= 3) {
flag = true;
}
} catch (Exception e) {
flag = false;
}
return flag;
}
//通用匹配
public static boolean find(String regexStr, String input) {
boolean flag;
try {
Pattern regex = Pattern.compile(regexStr);
Matcher matcher = regex.matcher(input);
// 部分进行匹配
flag = matcher.find();
} catch (Exception e) {
flag = false;
}
return flag;
} }
/**
* 获取随机验证码
*/
public static String getValidateCode() {
SecureRandom random = new SecureRandom();
try {
random = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage());
}
StringBuilder validateCode = new StringBuilder();
for (int i = 0; i < 6; i++) {
validateCode.append(random.nextInt(10));
}
return validateCode.toString();
}
/** /**
* 随机生成指定长度的字符串 * 随机生成指定长度的字符串
* *
...@@ -53,8 +180,8 @@ public class CommonUtil { ...@@ -53,8 +180,8 @@ public class CommonUtil {
int maxNum = 36; int maxNum = 36;
int i = -1; int i = -1;
int count = 0; int count = 0;
char[] str = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', char[] str = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
StringBuilder pwd = new StringBuilder(""); StringBuilder pwd = new StringBuilder("");
SecureRandom secureRandom = null; SecureRandom secureRandom = null;
try { try {
...@@ -75,7 +202,6 @@ public class CommonUtil { ...@@ -75,7 +202,6 @@ public class CommonUtil {
} }
public static String getSystemTime() { public static String getSystemTime() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式
String time = df.format(new Date()); String time = df.format(new Date());
...@@ -84,7 +210,7 @@ public class CommonUtil { ...@@ -84,7 +210,7 @@ public class CommonUtil {
public static boolean regularMessage(String message) { public static boolean regularMessage(String message) {
String regex = "^[0-9a-zA-Z]{1,}$"; String regex = "^[0-9a-zA-Z_]{1,}$";
return message.matches(regex); return message.matches(regex);
} }
...@@ -108,7 +234,73 @@ public class CommonUtil { ...@@ -108,7 +234,73 @@ public class CommonUtil {
} }
public static String getServerParentDirectory() { public static String getServerParentDirectory() {
return new File(new ApplicationHome(Constant.class).getSource().getParentFile().getPath()).getParent(); return new File(new ApplicationHome(Constant.class).getSource().getParentFile().getPath()).getParent() + File.separator + "lib";
}
/**
* 名字脱敏
* 规则,张三丰,脱敏为:张*丰
*
* @param name
* @return
*/
public static String nameDesensitization(String name) {
// 已经脱敏了直接返回
if (name == null || name.contains("*")) {
return name;
}
if (name == null || name.isEmpty()) {
return "";
}
String myName = null;
char[] chars = name.toCharArray();
if (chars.length == 1) {
myName = name;
}
if (chars.length == 2) {
myName = StringUtils.overlay(name, "*", 1, 2);
}
if (chars.length > 2) {
int n = chars.length - 2;
StringBuilder s = new StringBuilder();
for (int i = 0; i < n; i++) {
s.append("*");
}
myName = StringUtils.overlay(name, String.valueOf(s), 1, chars.length - 1);
}
return myName;
}
//身份证前三后四脱敏
public static String idCardEncrypt(String idcard) {
if (idcard == null || idcard.length() == 0 || idcard.contains("*")) {
return idcard;
}
if (StringUtils.isEmpty(idcard) || (idcard.length() < 8)) {
return idcard;
}
String res = StringUtils.overlay(idcard, "**************", 0, 14);
return res;
}
public static String getCurDateStr() {
Date date = new Date();
String pattern = "yyyy-MM-dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
return simpleDateFormat.format(date);
}
// 用于测试存储型xss
public static Object reverseData(Object obj, Class clazz) {
HashMap<String, Object> resMap = new HashMap<>();
resMap.put("data", obj);
if (!PubUtils.isNull()) {
return ResResult.success().goRecord(resMap);
} else {
return null;
}
} }
public static String getLibFilePathByFileName(String fileName) { public static String getLibFilePathByFileName(String fileName) {
...@@ -123,5 +315,4 @@ public class CommonUtil { ...@@ -123,5 +315,4 @@ public class CommonUtil {
} }
return ""; return "";
} }
} }
package iot.sixiang.license.util;
import iot.sixiang.license.handler.IotLicenseException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Title: EmailUtils
* Description:
*
* @author YFW
* @version V1.0
* @date 2020-05-23
*/
@Slf4j
@Component
public class EmailUtils {
Logger logger = LoggerFactory.getLogger(EmailUtils.class);
@Value("${spring.mail.username}")
private String from;
@Resource
public JavaMailSender mailSender;
public void sendSimpleMail(String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
//发件人
message.setFrom(from);
//目标
message.setTo(to);
//主题
message.setSubject(subject);
//内容
message.setText(content);
try {
mailSender.send(message);
logger.info("一份简单邮件已发送。");
} catch (Exception e) {
logger.error("发送简单邮件时发生异常!", e);
throw new IotLicenseException(405, "短信邮件发送失败");
}
}
}
//package iot.sixiang.license.xss;
//
///**
// * Title: AntiSamyConfig
// * Description: TODO
// *
// * @author tianlai3
// * @date 2022-07-17 01:18:02
// */
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.fasterxml.jackson.databind.module.SimpleModule;
//import org.springframework.boot.web.servlet.FilterRegistrationBean;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
//
//import javax.servlet.Filter;
//
//
//@Configuration
//public class AntiSamyConfig {
//
// /**
// * 配置XSS过滤器
// *
// * @return FilterRegistrationBean
// */
// @Bean
// public FilterRegistrationBean<Filter> filterRegistrationBean() {
// FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>(new XssFilter2());
// filterRegistrationBean.addUrlPatterns("/iot_license/*");
// filterRegistrationBean.setOrder(1);
// return filterRegistrationBean;
// }
//
// /**
// * 用于过滤Json类型数据的解析器
// *
// * @param builder Jackson2ObjectMapperBuilder
// * @return ObjectMapper
// */
// @Bean
// public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
// // 创建解析器
// ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// // 注册解析器
// SimpleModule simpleModule = new SimpleModule("XssStringJsonSerializer");
// simpleModule.addSerializer(new XssRequestWrapper2.XssStringJsonSerializer());
// objectMapper.registerModule(simpleModule);
// return objectMapper;
// }
//}
\ No newline at end of file
package iot.sixiang.license.xss;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* @Author m33
* @Date 2022/7/17 11:42
* @Description
*/
public class BeanCopyUtil extends BeanUtils {
/**
* 集合数据的拷贝
* @param sources: 数据源类
* @param target: 目标类::new(eg: UserVO::new)
* @return
*/
public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) {
return copyListProperties(sources, target, null);
}
/**
* 带回调函数的集合数据的拷贝(可自定义字段拷贝规则)
* @param sources: 数据源类
* @param target: 目标类::new(eg: UserVO::new)
* @param callBack: 回调函数
* @return
*/
public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target, BeanCopyUtilCallBack<S, T> callBack) {
List<T> list = new ArrayList<>(sources.size());
for (S source : sources) {
T t = target.get();
copyProperties(source, t);
list.add(t);
}
return list;
}
}
package iot.sixiang.license.xss;
/**
* @Author m33
* @Date 2022/7/17 11:43
* @Description
*/
@FunctionalInterface
public interface BeanCopyUtilCallBack <S, T> {
/**
* 定义默认回调方法
* @param t
* @param s
*/
void callBack(S t, T s);
}
package iot.sixiang.license.xss;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
/**
* @Author m33
* @Date 2022/6/29 13:59
* @Description
*/
@Configuration
public class XSSFilterConfig {
@Bean
@DependsOn("xssFilter")
public FilterRegistrationBean filterRegistrationBean() {
System.out.println("===================filterRegistrationBean");
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new XssFilter());
registration.addUrlPatterns("/*");
registration.addInitParameter("paramName", "paramValue");
registration.setName("xssFilter");
return registration;
}
}
...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Component; ...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Component;
import javax.servlet.*; import javax.servlet.*;
import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
...@@ -25,16 +26,18 @@ public class XssFilter implements Filter { ...@@ -25,16 +26,18 @@ public class XssFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(XssFilter.class); private static final Logger LOGGER = LoggerFactory.getLogger(XssFilter.class);
@Override @Override
public void init(FilterConfig filterConfig) throws ServletException { public void init(FilterConfig filterConfig) {
LOGGER.info("==============> 进入init XssFilter"); LOGGER.info("==============> 进入init XssFilter");
} }
@Override @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException { throws IOException, ServletException {
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(req);
LOGGER.info("========>进入XSS过滤器"); LOGGER.info("========>进入XSS过滤器");
chain.doFilter(xssRequest, response); chain.doFilter(xssRequest, resp);
LOGGER.info("=========>过滤器XSS执行完"); LOGGER.info("=========>过滤器XSS执行完");
} }
......
//package iot.sixiang.license.xss;
//
//import javax.servlet.*;
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletResponse;
//import java.io.IOException;
//
//
//public class XssFilter2 implements Filter {
//
// private FilterConfig filterConfig;
//
// @Override
// public void init(FilterConfig filterConfig) throws ServletException {
// this.filterConfig = filterConfig;
// }
//
// @Override
// public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
// throws IOException, ServletException {
// // 拦截请求,处理XSS过滤
// HttpServletRequest req = (HttpServletRequest) request;
// HttpServletResponse resp = (HttpServletResponse) response;
// XssRequestWrapper2 xssRequest = new XssRequestWrapper2(req);
//
// chain.doFilter(xssRequest, resp);
// }
//
// @Override
// public void destroy() {
// this.filterConfig = null;
// }
//}
\ No newline at end of file
package iot.sixiang.license.xss; package iot.sixiang.license.xss;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import iot.sixiang.license.consts.ResultCode;
import iot.sixiang.license.handler.IotLicenseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.owasp.esapi.ESAPI; import org.owasp.esapi.ESAPI;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static java.util.regex.Pattern.*; import static java.util.regex.Pattern.*;
...@@ -13,12 +25,121 @@ import static java.util.regex.Pattern.*; ...@@ -13,12 +25,121 @@ import static java.util.regex.Pattern.*;
* @Date 2022/7/4 11:24 * @Date 2022/7/4 11:24
* @Description * @Description
*/ */
@Slf4j
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* post请求体
*/
private byte[] body;
/**
* 是否是文件上传
*/
private boolean fileUpload = false;
/**
* sql注入正则
*/
private static String badStrReg =
"\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) { public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) throws IOException {
super(servletRequest); super(servletRequest);
String sessionStream = getBodyString(servletRequest);
body = sessionStream.getBytes(StandardCharsets.UTF_8);
}
private String getBodyString(HttpServletRequest httpservletrequest) throws IOException {
StringBuilder sb = new StringBuilder();
InputStream ins = httpservletrequest.getInputStream();
boolean isMultipartContent = ServletFileUpload.isMultipartContent(httpservletrequest);
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(httpservletrequest.getSession().getServletContext());
boolean isMultipart = commonsMultipartResolver.isMultipart(httpservletrequest);
if (isMultipartContent || isMultipart) {
fileUpload = true;
}
try (BufferedReader isr = new BufferedReader(new InputStreamReader(ins, StandardCharsets.UTF_8))) {
String line = "";
while ((line = isr.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
throw e;
}
String res = sb.toString();
return res;
}
/**
* 过滤请求体 json 格式的
*
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream(){
// 非文件上传进行过滤
if (!fileUpload) {
// 获取body中的请求参数
String requestString = new String(body, StandardCharsets.UTF_8);
if(requestString.startsWith("[")) {
List<String> strings = JSONArray.parseArray(requestString, String.class);
for (String string : strings) {
checkSqlAndXss(string);
}
} else {
checkSqlAndXss(new String(body, StandardCharsets.UTF_8));
}
}
// 将请求体参数流转 -- 流读取一次就会消失,所以我们事先读取之后就存在byte数组里边方便流转
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
log.debug("setReadListener");
}
};
}
public void checkSqlAndXss(String str) {
JSONObject json = JSONObject.parseObject(str);
// 校验并过滤xss攻击和sql注入
for (String k : json.keySet()) {
cleanSQLInject(cleanXSS(json.getString(k)));
}
}
/**
* 过滤sql注入 -- 需要增加通配,过滤大小写组合
*
* @param src 单个参数值
* @return
*/
public String cleanSQLInject(String src) {
// 非法sql注入正则
Pattern sqlPattern = Pattern.compile(badStrReg, Pattern.CASE_INSENSITIVE);
if (sqlPattern.matcher(src.toUpperCase()).find()) {
log.error("sql注入检查:输入信息存在SQL攻击!");
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), "sql注入检查:参数含有非法攻击字符,已禁止继续访问!!");
}
return src;
} }
@Override @Override
...@@ -37,7 +158,7 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { ...@@ -37,7 +158,7 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
String[] encodedValues = new String[count]; String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
cleanSQLInject(values[i]);
encodedValues[i] = cleanXSS(values[i]); encodedValues[i] = cleanXSS(values[i]);
} }
...@@ -57,6 +178,8 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { ...@@ -57,6 +178,8 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
} }
cleanSQLInject(value);
return cleanXSS(value); return cleanXSS(value);
} }
...@@ -74,28 +197,9 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { ...@@ -74,28 +197,9 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
} }
// private String cleanXSS(String value) {
//
// //You'll need to remove the spaces from the html entities below
//
// value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
//
// value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
//
// value = value.replaceAll("'", "& #39;");
//
// value = value.replaceAll("eval\\((.*)\\)", "");
//
// value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
//
// value = value.replaceAll("script", "");
//
// return value;
//
// }
private String cleanXSS(String value) { private String cleanXSS(String value) {
if (value != null) { if (value != null && value.length() != 0) {
// 推荐使用ESAPI库来避免脚本攻击 // 推荐使用ESAPI库来避免脚本攻击
value = ESAPI.encoder().canonicalize(value); value = ESAPI.encoder().canonicalize(value);
// 避免空字符串 // 避免空字符串
...@@ -142,7 +246,9 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { ...@@ -142,7 +246,9 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
// 避免 onXX= 表达式 // 避免 onXX= 表达式
scriptPattern = Pattern.compile("on.*(.*?)=", CASE_INSENSITIVE | MULTILINE | DOTALL); scriptPattern = Pattern.compile("on.*(.*?)=", CASE_INSENSITIVE | MULTILINE | DOTALL);
value = scriptPattern.matcher(value).replaceAll(""); value = scriptPattern.matcher(value).replaceAll("");
if (value.length() == 0) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), "参数含有非法攻击字符,已禁止继续访问!!");
}
} }
return value; return value;
} }
......
//package iot.sixiang.license.xss;
//
//import com.fasterxml.jackson.core.JsonGenerator;
//import com.fasterxml.jackson.databind.JsonSerializer;
//import com.fasterxml.jackson.databind.SerializerProvider;
//import lombok.extern.slf4j.Slf4j;
//import org.apache.commons.lang3.StringUtils;
//import org.apache.commons.text.StringEscapeUtils;
//import org.owasp.validator.html.*;
//
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletRequestWrapper;
//import java.io.IOException;
//import java.io.UnsupportedEncodingException;
//import java.net.URLDecoder;
//import java.util.Iterator;
//import java.util.Map;
//import java.util.Objects;
//
///**
// * Title: XssRequestWrapper2
// * Description: TODO
// *
// * @author tianlai3
// * @date 2022-07-16 22:48:55
// */
//@Slf4j
//public class XssRequestWrapper2 extends HttpServletRequestWrapper {
// private static Policy policy = null;
//
// static {
// try {
// // 获取策略文件路径,策略文件需要放到项目的classpath下
// String antiSamyPath = Objects
// .requireNonNull(XssRequestWrapper2.class.getClassLoader().getResource("antisamy-ebay.xml")).getFile();
// log.info(antiSamyPath);
// // 获取的文件路径中有空格时,空格会被替换为%20,在new一个File对象时会出现找不到路径的错误
// // 对路径进行解码以解决该问题
// antiSamyPath = URLDecoder.decode(antiSamyPath, "utf-8");
// log.info(antiSamyPath);
// // 指定策略文件
// policy = Policy.getInstance(antiSamyPath);
// } catch (UnsupportedEncodingException | PolicyException e) {
// log.warn(e.getMessage());
// }
// }
//
// public XssRequestWrapper2(HttpServletRequest request) {
// super(request);
// }
//
// /**
// * 过滤请求头
// *
// * @param name 参数名
// * @return 参数值
// */
// @Override
// public String getHeader(String name) {
// String header = super.getHeader(name);
// // 如果Header为空,则直接返回,否则进行清洗
// return StringUtils.isBlank(header) ? header : xssClean(header);
// }
//
// /**
// * 过滤请求参数
// *
// * @param name 参数名
// * @return 参数值
// */
// @Override
// public String getParameter(String name) {
// String parameter = super.getParameter(name);
// // 如果Parameter为空,则直接返回,否则进行清洗
// return StringUtils.isBlank(parameter) ? parameter : xssClean(parameter);
// }
//
// /**
// * 过滤请求参数(一个参数可以有多个值)
// *
// * @param name 参数名
// * @return 参数值数组
// */
// @Override
// public String[] getParameterValues(String name) {
// String[] parameterValues = super.getParameterValues(name);
// if (parameterValues != null) {
// int length = parameterValues.length;
// String[] newParameterValues = new String[length];
// for (int i = 0; i < length; i++) {
// log.info("AntiSamy清理之前的参数值:" + parameterValues[i]);
// // 清洗参数
// newParameterValues[i] = xssClean(parameterValues[i]);
// log.info("AntiSamy清理之后的参数值:" + newParameterValues[i]);
// }
// return newParameterValues;
// }else{
// return null;
// }
// }
//
//// @Override
//// public String[] getParameterValues(String parameter) {
////
//// String[] values = super.getParameterValues(parameter);
////
//// if (values == null) {
////
//// return null;
////
//// }
////
//// int count = values.length;
////
//// String[] encodedValues = new String[count];
////
//// for (int i = 0; i < count; i++) {
////// cleanSQLInject(values[i]);
//// encodedValues[i] = xssClean(values[i]);
////
//// }
////
//// return encodedValues;
////
//// }
//// @Override
//// public Map<String, String[]> getParameterMap() {
//// Map<String, String[]> requestMap = super.getParameterMap();
////
////
//// requestMap.forEach((key, value) -> {
//// for (int i = 0; i < value.length; i++) {
//// log.info(value[i]);
//// value[i] = xssClean(value[i]);
//// log.info(value[i]);
//// }
//// });
//// return requestMap;
//// }
//
// /**
// * 使用AntiSamy清洗数据
// *
// * @param value 需要清洗的数据
// * @return 清洗后的数据
// */
// private String xssClean(String value) {
// try {
// AntiSamy antiSamy = new AntiSamy();
// // 使用AntiSamy清洗数据
// final CleanResults cleanResults = antiSamy.scan(value, policy);
// // 获得安全的HTML输出
// value = cleanResults.getCleanHTML();
// // 对转义的HTML特殊字符(<、>、"等)进行反转义,因为AntiSamy调用scan方法时会将特殊字符转义
// return StringEscapeUtils.unescapeHtml4(value);
// } catch (ScanException | PolicyException e) {
// log.warn(e.getMessage());
// }
// return value;
// }
//
// /**
// * 通过修改Json序列化的方式来完成Json格式的XSS过滤
// */
// public static class XssStringJsonSerializer extends JsonSerializer<String> {
//
// @Override
// public Class<String> handledType() {
// return String.class;
// }
//
// @Override
// public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// if (!StringUtils.isBlank(value)) {
// try {
// AntiSamy antiSamy = new AntiSamy();
// final CleanResults cleanResults = antiSamy.scan(value, XssRequestWrapper2.policy);
// gen.writeString(StringEscapeUtils.unescapeHtml4(cleanResults.getCleanHTML()));
// } catch (ScanException | PolicyException e) {
// log.warn(e.getMessage());
// }
// }
// }
// }
//}
\ No newline at end of file
package iot.sixiang.license.xss;
import iot.sixiang.license.consts.ResultCode;
import iot.sixiang.license.handler.IotLicenseException;
import lombok.extern.slf4j.Slf4j;
import org.owasp.esapi.ESAPI;
import java.util.regex.Pattern;
import static java.util.regex.Pattern.*;
/**
* Title: XssUtil
* Description: TODO
*
* @author tianlai3
* @date 2022-07-17 15:27:52
*/
@Slf4j
public class XssUtil {
public static String checkXSS(String value) {
if (value != null && value.length() != 0) {
// 推荐使用ESAPI库来避免脚本攻击
value = ESAPI.encoder().canonicalize(value);
// 避免空字符串
value = value.replaceAll("", "");
// 避免script 标签
Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
//避免src形式的表达式
//scriptPattern = compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", CASE_INSENSITIVE | MULTILINE | DOTALL);
//value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", CASE_INSENSITIVE | MULTILINE | DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// 删除单个的 </script> 标签
scriptPattern = Pattern.compile("</script>", CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// 删除单个的<script ...> 标签
scriptPattern = Pattern.compile("<script(.*?)>", CASE_INSENSITIVE | MULTILINE | DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// 避免 eval(...) 形式表达式
scriptPattern = Pattern.compile("eval\\((.*?)\\)", CASE_INSENSITIVE | MULTILINE | DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// 避免 e­xpression(...) 表达式
scriptPattern = Pattern.compile("expression\\((.*?)\\)", CASE_INSENSITIVE | MULTILINE | DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// 避免 javascript: 表达式
scriptPattern = Pattern.compile("javascript:", CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// 避免 vbscript: 表达式
scriptPattern = Pattern.compile("vbscript:", CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// 避免 onload= 表达式
scriptPattern = Pattern.compile("onload(.*?)=", CASE_INSENSITIVE | MULTILINE | DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// 避免 onXX= 表达式
scriptPattern = Pattern.compile("on.*(.*?)=", CASE_INSENSITIVE | MULTILINE | DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
if (value.length() == 0) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), "参数含有非法攻击字符,已禁止继续访问!!");
}
return value;
} else {
return null;
}
}
}
...@@ -77,9 +77,9 @@ ESAPI.Validator=org.owasp.esapi.reference.DefaultValidator ...@@ -77,9 +77,9 @@ ESAPI.Validator=org.owasp.esapi.reference.DefaultValidator
# ESAPI Authenticator # ESAPI Authenticator
# #
Authenticator.AllowedLoginAttempts=3 Authenticator.AllowedLoginAttempts=3
Authenticator.MaxOldPasswordHashes=13 Authenticator.MaxOldPasswordHashes=ENC(F0TJ9iT6D4VW8xVjZf9Nqw==)
Authenticator.UsernameParameterName=username Authenticator.UsernameParameterName=username
Authenticator.PasswordParameterName=password Authenticator.PasswordParameterName=ENC(F0TJ9iT6D4VW8xVjZf9Nqw==)
# RememberTokenDuration (in days) # RememberTokenDuration (in days)
Authenticator.RememberTokenDuration=14 Authenticator.RememberTokenDuration=14
# Session Timeouts (in minutes) # Session Timeouts (in minutes)
...@@ -304,9 +304,9 @@ Encryptor.KDF.PRF=HmacSHA256 ...@@ -304,9 +304,9 @@ Encryptor.KDF.PRF=HmacSHA256
HttpUtilities.UploadDir=C:\\ESAPI\\testUpload HttpUtilities.UploadDir=C:\\ESAPI\\testUpload
HttpUtilities.UploadTempDir=C:\\temp HttpUtilities.UploadTempDir=C:\\temp
# Force flags on cookies, if you use HttpUtilities to set cookies # Force flags on cookies, if you use HttpUtilities to set cookies
HttpUtilities.ForceHttpOnlySession=false #HttpUtilities.ForceHttpOnlySession=false
HttpUtilities.ForceSecureSession=false HttpUtilities.ForceSecureSession=false
HttpUtilities.ForceHttpOnlyCookies=true #HttpUtilities.ForceHttpOnlyCookies=true
HttpUtilities.ForceSecureCookies=true HttpUtilities.ForceSecureCookies=true
# Maximum size of HTTP header key--the validator regex may have additional values. # Maximum size of HTTP header key--the validator regex may have additional values.
HttpUtilities.MaxHeaderNameSize=256 HttpUtilities.MaxHeaderNameSize=256
......
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!--
W3C rules retrieved from:
http://www.w3.org/TR/html401/struct/global.html
-->
<anti-samy-rules xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="antisamy.xsd">
<directives>
<directive name="omitXmlDeclaration" value="true"/>
<directive name="omitDoctypeDeclaration" value="true"/>
<directive name="maxInputSize" value="20000"/>
<directive name="useXHTML" value="true"/>
<directive name="formatOutput" value="true"/>
<!--
remember, this won't work for relative URIs - AntiSamy doesn't
know anything about the URL or your web structure
-->
<directive name="embedStyleSheets" value="false"/>
</directives>
<common-regexps>
<!--
From W3C:
This attribute assigns a class name or set of class names to an
element. Any number of elements may be assigned the same class
name or names. Multiple class names must be separated by white
space characters.
-->
<!-- The 16 colors defined by the HTML Spec (also used by the CSS Spec) -->
<regexp name="colorName" value="(aqua|black|blue|fuchsia|gray|grey|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)"/>
<!-- HTML/CSS Spec allows 3 or 6 digit hex to specify color -->
<regexp name="colorCode" value="(#([0-9a-fA-F]{6}|[0-9a-fA-F]{3}))"/>
<regexp name="anything" value=".*"/>
<regexp name="numberOrPercent" value="(\d)+(%{0,1})"/>
<regexp name="paragraph" value="([\p{L}\p{N},'\.\s\-_\(\)]|&amp;[0-9]{2};)*"/>
<regexp name="htmlId" value="[a-zA-Z0-9\:\-_\.]+"/>
<regexp name="htmlTitle" value="[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&amp;]*"/> <!-- force non-empty with a '+' at the end instead of '*' -->
<regexp name="htmlClass" value="[a-zA-Z0-9\s,\-_]+"/>
<regexp name="onsiteURL" value="^(?!//)(?![\p{L}\p{N}\\\.\#@\$%\+&amp;;\-_~,\?=/!]*(&amp;colon))[\p{L}\p{N}\\\.\#@\$%\+&amp;;\-_~,\?=/!]*"/>
<regexp name="offsiteURL" value="(\s)*((ht|f)tp(s?)://|mailto:)[\p{L}\p{N}]+[\p{L}\p{N}\p{Zs}\.\#@\$%\+&amp;;:\-_~,\?=/!\(\)]*(\s)*"/>
<regexp name="boolean" value="(true|false)"/>
<regexp name="singlePrintable" value="[a-zA-Z0-9]{1}"/> <!-- \w allows the '_' character -->
<!-- This is for elements (ex: elemName { ... }) -->
<regexp name="cssElementSelector" value="[a-zA-Z0-9\-_]+|\*"/>
<!-- This is to list out any element names that are *not* valid -->
<regexp name="cssElementExclusion" value=""/>
<!-- This if for classes (ex: .className { ... }) -->
<regexp name="cssClassSelector" value="\.[a-zA-Z0-9\-_]+"/>
<!-- This is to list out any class names that are *not* valid -->
<regexp name="cssClassExclusion" value=""/>
<!-- This is for ID selectors (ex: #myId { ... } -->
<regexp name="cssIDSelector" value="#[a-zA-Z0-9\-_]+"/>
<!-- This is to list out any IDs that are *not* valid - FIXME: What should the default be to avoid div hijacking? *? -->
<regexp name="cssIDExclusion" value=""/>
<!-- This is for pseudo-element selector (ex. foo:pseudo-element { ... } -->
<regexp name="cssPseudoElementSelector" value=":[a-zA-Z0-9\-_]+"/>
<!-- This is to list out any psuedo-element names that are *not* valid -->
<regexp name="cssPsuedoElementExclusion" value=""/>
<!-- This is for attribute selectors (ex. foo[attr=value] { ... } -->
<regexp name="cssAttributeSelector" value="\[[a-zA-Z0-9\-_]+((=|~=|\|=){1}[a-zA-Z0-9\-_]+){1}\]"/>
<!-- This is to list out any attribute names that are *not* valid -->
<regexp name="cssAttributeExclusion" value=""/>
<!-- This is for resources referenced from CSS (such as background images and other imported stylesheets) -->
<regexp name="cssOnsiteUri" value="url\(([\p{L}\p{N}\\/\.\?=\#&amp;;\-_~]+|\#(\w)+)\)"/>
<regexp name="cssOffsiteUri" value="url\((\s)*((ht|f)tp(s?)://)[\p{L}\p{N}]+[~\p{L}\p{N}\p{Zs}\-_\.@#$%&amp;;:,\?=/\+!]*(\s)*\)"/>
<!-- This if for CSS Identifiers -->
<regexp name="cssIdentifier" value="[a-zA-Z0-9\-_]+"/>
<!-- This is for comments within CSS (ex. /* comment */) -->
<regexp name="cssCommentText" value="[\p{L}\p{N}\-_,\/\\\.\s\(\)!\?\=\$#%\^&amp;:&quot;']+"/>
<regexp name="integer" value="(-|\+)?[0-9]+"/>
<regexp name="positiveInteger" value="(\+)?[0-9]+"/>
<regexp name="number" value="(-|\+)?([0-9]+(\.[0-9]+)?)"/>
<regexp name="angle" value="(-|\+)?([0-9]+(\.[0-9]+)?)(deg|grads|rad)"/>
<regexp name="time" value="([0-9]+(\.[0-9]+)?)(ms|s)"/>
<regexp name="frequency" value="([0-9]+(\.[0-9]+)?)(hz|khz)"/>
<regexp name="length" value="((-|\+)?0|(-|\+)?([0-9]+(\.[0-9]+)?)(em|ex|px|in|cm|mm|pt|pc))"/>
<regexp name="positiveLength" value="((\+)?0|(\+)?([0-9]+(\.[0-9]+)?)(em|ex|px|in|cm|mm|pt|pc))"/>
<regexp name="percentage" value="(-|\+)?([0-9]+(\.[0-9]+)?)%"/>
<regexp name="positivePercentage" value="(\+)?([0-9]+(\.[0-9]+)?)%"/>
<regexp name="absolute-size" value="(xx-small|x-small|small|medium|large|x-large|xx-large)"/>
<regexp name="relative-size" value="(larger|smaller)"/>
<!-- Used for CSS Color specifications (complex regexp expresses integer values of 0-255) -->
<regexp name="rgbCode" value="rgb\(([1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]),([1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]),([1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])\)"/>
<!-- CSS2 Allowed System Color Values -->
<regexp name="systemColor" value="(activeborder|activecaption|appworkspace|background|buttonface|buttonhighlight|buttonshadow|buttontext|captiontext|graytext|highlight|highlighttext|inactiveborder|inactivecaption|inactivecaptiontext|infobackground|infotext|menu|menutext|scrollbar|threeddarkshadow|threedface|threedhighlight|threedlightshadow|threedshadow|window|windowframe|windowtext)"/>
</common-regexps>
<!--
Tag.name = a, b, div, body, etc.
Tag.action = filter: remove tags, but keep content, validate: keep content as long as it passes rules, remove: remove tag and contents
Attribute.name = id, class, href, align, width, etc.
Attribute.onInvalid = what to do when the attribute is invalid, e.g., remove the tag (removeTag), remove the attribute (removeAttribute), filter the tag (filterTag)
Attribute.description = What rules in English you want to tell the users they can have for this attribute. Include helpful things so they'll be able to tune their HTML
-->
<!--
Some attributes are common to all (or most) HTML tags. There aren't many that qualify for this. You have to make sure there's no
collisions between any of these attribute names with attribute names of other tags that are for different purposes.
-->
<common-attributes>
<!-- Common to all HTML tags -->
<attribute name="id" description="The 'id' of any HTML attribute should not contain anything besides letters and numbers">
<regexp-list>
<regexp name="htmlId"/>
</regexp-list>
</attribute>
<attribute name="class" description="The 'class' of any HTML attribute is usually a single word, but it can also be a list of class names separated by spaces">
<regexp-list>
<regexp name="htmlClass"/>
</regexp-list>
</attribute>
<attribute name="lang" description="The 'lang' attribute tells the browser what language the element's attribute values and content are written in">
<regexp-list>
<regexp value="[a-zA-Z]{2,20}"/>
</regexp-list>
</attribute>
<attribute name="title" description="The 'title' attribute provides text that shows up in a 'tooltip' when a user hovers their mouse over the element">
<regexp-list>
<regexp name="htmlTitle"/>
</regexp-list>
</attribute>
<attribute name="alt" description="The 'alt' attribute provides alternative text to users when its visual representation is not available">
<regexp-list>
<regexp name="paragraph"/>
</regexp-list>
</attribute>
<!-- the "style" attribute will be validated by an inline stylesheet scanner, so no need to define anything here - i hate having to special case this but no other choice -->
<attribute name="style" description="The 'style' attribute provides the ability for users to change many attributes of the tag's contents using a strict syntax"/>
<attribute name="media">
<regexp-list>
<regexp value="[a-zA-Z0-9,\-\s]+"/>
</regexp-list>
<literal-list>
<literal value="screen"/>
<literal value="tty"/>
<literal value="tv"/>
<literal value="projection"/>
<literal value="handheld"/>
<literal value="print"/>
<literal value="braille"/>
<literal value="aural"/>
<literal value="all"/>
</literal-list>
</attribute>
<!-- Anchor related -->
<!-- onInvalid="filterTag" has been removed as per suggestion at OWASP SJ 2007 - just "name" is valid -->
<attribute name="href">
<regexp-list>
<regexp name="onsiteURL"/>
</regexp-list>
</attribute>
<attribute name="name">
<regexp-list>
<regexp value="[a-zA-Z0-9\-_\$]+"/>
<!--
have to allow the $ for .NET controls - although,
will users be supplying input that has server-generated
.NET control names? methinks not, but i want to pass my
test cases
-->
</regexp-list>
</attribute>
<attribute name="shape" description="The 'shape' attribute defines the shape of the selectable area">
<literal-list>
<literal value="default"/>
<literal value="rect"/>
<literal value="circle"/>
<literal value="poly"/>
</literal-list>
</attribute>
<!-- Table attributes -->
<attribute name="border">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="cellpadding">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="cellspacing">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="colspan">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="rowspan">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="background">
<regexp-list>
<regexp name="onsiteURL"/>
</regexp-list>
</attribute>
<attribute name="bgcolor">
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
</regexp-list>
</attribute>
<attribute name="abbr">
<regexp-list>
<regexp name="paragraph"/>
</regexp-list>
</attribute>
<attribute name="headers" description="The 'headers' attribute is a space-separated list of cell IDs">
<regexp-list>
<regexp value="[a-zA-Z0-9\s*]*"/>
</regexp-list>
</attribute>
<attribute name="charoff">
<regexp-list>
<regexp value="numberOrPercent"/>
</regexp-list>
</attribute>
<attribute name="char">
<regexp-list>
<regexp value=".{0,1}"/>
</regexp-list>
</attribute>
<attribute name="axis" description="The 'headers' attribute is a comma-separated list of related header cells">
<regexp-list>
<regexp value="[a-zA-Z0-9\s*,]*"/>
</regexp-list>
</attribute>
<attribute name="nowrap" description="The 'nowrap' attribute tells the browser not to wrap text that goes over one line">
<regexp-list>
<regexp name="anything"/>
<!-- <regexp value="(nowrap){0,1}"/> -->
</regexp-list>
</attribute>
<!-- Common positioning attributes -->
<attribute name="width">
<regexp-list>
<regexp name="numberOrPercent"/>
</regexp-list>
</attribute>
<attribute name="height">
<regexp-list>
<regexp name="numberOrPercent"/>
</regexp-list>
</attribute>
<attribute name="align" description="The 'align' attribute of an HTML element is a direction word, like 'left', 'right' or 'center'">
<literal-list>
<literal value="center"/>
<literal value="middle"/>
<literal value="left"/>
<literal value="right"/>
<literal value="justify"/>
<literal value="char"/>
</literal-list>
</attribute>
<attribute name="valign" description="The 'valign' attribute of an HTML attribute is a direction word, like 'baseline','bottom','middle' or 'top'">
<literal-list>
<literal value="baseline"/>
<literal value="bottom"/>
<literal value="middle"/>
<literal value="top"/>
</literal-list>
</attribute>
<!-- Intrinsic JavaScript Events -->
<attribute name="onFocus" description="The 'onFocus' event is executed when the control associated with the tag gains focus">
<literal-list>
<literal value="javascript:void(0)"/>
<literal value="javascript:history.go(-1)"/>
</literal-list>
</attribute>
<attribute name="onBlur" description="The 'onBlur' event is executed when the control associated with the tag loses focus">
<literal-list>
<literal value="javascript:void(0)"/>
<literal value="javascript:history.go(-1)"/>
</literal-list>
</attribute>
<attribute name="onClick" description="The 'onClick' event is executed when the control associated with the tag is clicked">
<literal-list>
<literal value="javascript:void(0)"/>
<literal value="javascript:history.go(-1)"/>
</literal-list>
</attribute>
<attribute name="onDblClick" description="The 'onDblClick' event is executed when the control associated with the tag is clicked twice immediately">
<literal-list>
<literal value="javascript:void(0)"/>
<literal value="javascript:history.go(-1)"/>
</literal-list>
</attribute>
<attribute name="onMouseDown" description="The 'onMouseDown' event is executed when the control associated with the tag is clicked but not yet released">
<literal-list>
<literal value="javascript:void(0)"/>
<literal value="javascript:history.go(-1)"/>
</literal-list>
</attribute>
<attribute name="onMouseUp" description="The 'onMouseUp' event is executed when the control associated with the tag is clicked after the button is released">
<literal-list>
<literal value="javascript:void(0)"/>
<literal value="javascript:history.go(-1)"/>
</literal-list>
</attribute>
<attribute name="onMouseOver" description="The 'onMouseOver' event is executed when the user's mouse hovers over the control associated with the tag">
<literal-list>
<literal value="javascript:void(0)"/>
<literal value="javascript:history.go(-1)"/>
</literal-list>
</attribute>
<attribute name="scope" description="The 'scope' attribute defines what's covered by the header cells">
<literal-list>
<literal value="row"/>
<literal value="col"/>
<literal value="rowgroup"/>
<literal value="colgroup"/>
</literal-list>
</attribute>
<!-- If you want users to be able to mess with tabindex, uncomment this -->
<!--
<attribute name="tabindex" description="...">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
-->
<!-- Input/form related common attributes -->
<attribute name="disabled">
<regexp-list>
<regexp name="anything"/>
</regexp-list>
</attribute>
<attribute name="readonly">
<regexp-list>
<regexp name="anything"/>
</regexp-list>
</attribute>
<attribute name="accesskey">
<regexp-list>
<regexp name="anything"/>
</regexp-list>
</attribute>
<attribute name="size">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="autocomplete">
<literal-list>
<literal value="on"/>
<literal value="off"/>
</literal-list>
</attribute>
<attribute name="rows">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="cols">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
</common-attributes>
<!--
This requires normal updates as browsers continue to diverge from the W3C and each other. As long as the browser wars continue
this is going to continue. I'm not sure war is the right word for what's going on. Doesn't somebody have to win a war after
a while? Even wars of attrition, surely?
-->
<global-tag-attributes>
<!-- Not valid in base, head, html, meta, param, script, style, and title elements. -->
<attribute name="id"/>
<attribute name="style"/>
<attribute name="title"/>
<attribute name="class"/>
<!-- Not valid in base, br, frame, frameset, hr, iframe, param, and script elements. -->
<attribute name="lang"/>
</global-tag-attributes>
<tags-to-encode>
<tag>g</tag>
<tag>grin</tag>
</tags-to-encode>
<tag-rules>
<!-- Tags related to JavaScript -->
<tag name="script" action="remove"/>
<tag name="noscript" action="validate"/> <!-- although no javascript can fire inside a noscript tag, css is still a viable attack vector -->
<!-- Frame & related tags -->
<tag name="iframe" action="remove"/>
<tag name="frameset" action="remove"/>
<tag name="frame" action="remove"/>
<!-- Form related tags -->
<tag name="label" action="validate">
<attribute name="for">
<regexp-list>
<regexp name="htmlId"/>
</regexp-list>
</attribute>
</tag>
<!-- All formatting tags -->
<tag name="h1" action="validate"/>
<tag name="h2" action="validate"/>
<tag name="h3" action="validate"/>
<tag name="h4" action="validate"/>
<tag name="h5" action="validate"/>
<tag name="h6" action="validate"/>
<tag name="p" action="validate">
<attribute name="align"/>
</tag>
<tag name="i" action="validate"/>
<tag name="b" action="validate"/>
<tag name="u" action="validate"/>
<tag name="strong" action="validate"/>
<tag name="em" action="validate"/>
<tag name="small" action="validate"/>
<tag name="big" action="validate"/>
<tag name="pre" action="validate"/>
<tag name="code" action="validate"/>
<tag name="cite" action="validate"/>
<tag name="samp" action="validate"/>
<tag name="sub" action="validate"/>
<tag name="sup" action="validate"/>
<tag name="strike" action="validate"/>
<tag name="center" action="validate"/>
<tag name="blockquote" action="validate"/>
<tag name="hr" action="validate"/>
<tag name="br" action="validate"/>
<tag name="font" action="validate">
<attribute name="color">
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
</regexp-list>
</attribute>
<attribute name="face">
<regexp-list>
<regexp value="[\w;, \-]+"/>
</regexp-list>
</attribute>
<attribute name="size">
<regexp-list>
<regexp value="(\+|-){0,1}(\d)+"/>
</regexp-list>
</attribute>
</tag>
<!-- Anchor and anchor related tags -->
<tag name="a" action="validate">
<!-- onInvalid="filterTag" has been removed as per suggestion at OWASP SJ 2007 - just "name" is valid -->
<attribute name="href"/>
<attribute name="onFocus"/>
<attribute name="onBlur"/>
<attribute name="nohref">
<regexp-list>
<regexp name="anything"/>
</regexp-list>
</attribute>
<attribute name="rel">
<literal-list>
<literal value="nofollow"/>
</literal-list>
</attribute>
<attribute name="name"/>
</tag>
<tag name="map" action="validate"/>
<!-- base tag removed per demo - this could be enabled with literal-list values you allow -->
<!--
<tag name="base" action="validate">
<attribute name="href"/>
</tag>
-->
<!-- Stylesheet Tags -->
<tag name="style" action="validate">
<attribute name="type">
<literal-list>
<literal value="text/css"/>
</literal-list>
</attribute>
<attribute name="media"/>
</tag>
<tag name="span" action="validate"/>
<tag name="div" action="validate">
<attribute name="align"/>
</tag>
<!-- <attribute name="id"/> what could an attacker do if they could overwrite an existing div definition? prolly something bad -->
<!-- <attribute name="class"/> what could an attacker do if they could specify any class in the namespace? prolly something bad -->
<!-- Image & image related tags -->
<tag name="img" action="validate">
<attribute name="src" onInvalid="removeTag">
<regexp-list>
<regexp name="onsiteURL"/>
<regexp name="offsiteURL"/>
</regexp-list>
</attribute>
<attribute name="name"/>
<attribute name="alt"/>
<attribute name="height"/>
<attribute name="width"/>
<attribute name="border"/>
<attribute name="align"/>
<attribute name="hspace">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="vspace">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
</tag>
<!-- no way to do this safely without hooking up the same code to @import to embed the remote stylesheet (malicious user could change offsite resource to be malicious after validation -->
<!-- <attribute name="href" onInvalid="removeTag"/> -->
<tag name="link" action="validate">
<!-- <attribute name="href" onInvalid="removeTag"/> -->
<attribute name="media"/>
<attribute name="type" onInvalid="removeTag">
<literal-list>
<literal value="text/css"/>
<literal value="application/rss+xml"/>
<literal value="image/x-icon"/>
</literal-list>
</attribute>
<attribute name="rel">
<literal-list>
<literal value="stylesheet"/>
<literal value="shortcut icon"/>
<literal value="search"/>
<literal value="copyright"/>
<literal value="top"/>
<literal value="alternate"/>
</literal-list>
</attribute>
</tag>
<!-- List tags -->
<tag name="ul" action="validate"/>
<tag name="ol" action="validate"/>
<tag name="li" action="validate"/>
<!-- Dictionary tags -->
<tag name="dd" action="truncate"/>
<tag name="dl" action="truncate"/>
<tag name="dt" action="truncate"/>
<!-- Table tags (tbody, thead, tfoot)-->
<tag name="thead" action="validate">
<attribute name="align"/>
<attribute name="char"/>
<attribute name="charoff"/>
<attribute name="valign"/>
</tag>
<tag name="tbody" action="validate">
<attribute name="align"/>
<attribute name="char"/>
<attribute name="charoff"/>
<attribute name="valign"/>
</tag>
<tag name="tfoot" action="validate">
<attribute name="align"/>
<attribute name="char"/>
<attribute name="charoff"/>
<attribute name="valign"/>
</tag>
<tag name="table" action="validate">
<attribute name="height"/>
<attribute name="width"/>
<attribute name="border"/>
<attribute name="bgcolor"/>
<attribute name="cellpadding"/>
<attribute name="cellspacing"/>
<attribute name="background"/>
<attribute name="align"/>
<attribute name="noresize">
<literal-list>
<literal value="noresize"/>
<literal value=""/>
</literal-list>
</attribute>
</tag>
<tag name="td" action="validate">
<attribute name="background"/>
<attribute name="bgcolor"/>
<attribute name="abbr"/>
<attribute name="axis"/>
<attribute name="headers"/>
<attribute name="scope"/>
<attribute name="nowrap"/>
<attribute name="height"/>
<attribute name="width"/>
<attribute name="align"/>
<attribute name="char"/>
<attribute name="charoff"/>
<attribute name="valign"/>
<attribute name="colspan"/>
<attribute name="rowspan"/>
</tag>
<tag name="th" action="validate">
<attribute name="abbr"/>
<attribute name="axis"/>
<attribute name="headers"/>
<attribute name="scope"/>
<attribute name="nowrap"/>
<attribute name="bgcolor"/>
<attribute name="height"/>
<attribute name="width"/>
<attribute name="align"/>
<attribute name="char"/>
<attribute name="charoff"/>
<attribute name="valign"/>
<attribute name="colspan"/>
<attribute name="rowspan"/>
</tag>
<tag name="tr" action="validate">
<attribute name="height"/>
<attribute name="width"/>
<attribute name="align"/>
<attribute name="valign"/>
<attribute name="char"/>
<attribute name="charoff"/>
<attribute name="background"/>
</tag>
<tag name="colgroup" action="validate">
<attribute name="span">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="width"/>
<attribute name="align"/>
<attribute name="char"/>
<attribute name="charoff"/>
<attribute name="valign"/>
</tag>
<tag name="col" action="validate">
<attribute name="align"/>
<attribute name="char"/>
<attribute name="charoff"/>
<attribute name="valign"/>
<attribute name="span">
<regexp-list>
<regexp name="number"/>
</regexp-list>
</attribute>
<attribute name="width"/>
</tag>
<tag name="fieldset" action="validate"/>
<tag name="legend" action="validate"/>
</tag-rules>
<!-- CSS validation processing rules -->
<css-rules>
<property name="azimuth" description="This property is most likely to be implemented by mixing the same signal into different channels at differing volumes.">
<literal-list>
<literal value="left-side"/>
<literal value="far-left"/>
<literal value="left"/>
<literal value="center-left"/>
<literal value="center"/>
<literal value="center-right"/>
<literal value="right"/>
<literal value="far-right"/>
<literal value="right-side"/>
<literal value="behind"/>
<literal value="leftwards"/>
<literal value="rightwards"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="angle"/>
</regexp-list>
</property>
<property name="background" description="The 'background' property is a shorthand property for setting the individual background properties (i.e., 'background-color', 'background-image', 'background-repeat', 'background-attachment' and 'background-position') at the same place in the style sheet.">
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="background-color"/>
<shorthand name="background-image"/>
<shorthand name="background-repeat"/>
<shorthand name="background-attachment"/>
<shorthand name="background-position"/>
</shorthand-list>
</property>
<property name="background-attachment" description="If a background image is specified, this property specifies whether it is fixed with regard to the viewport ('fixed') or scrolls along with the document ('scroll').">
<literal-list>
<literal value="scroll"/>
<literal value="fixed"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="background-color" description="This property sets the background color of an element, either a &lt;color&gt; value or the keyword 'transparent', to make the underlying colors shine through.">
<literal-list>
<literal value="transparent"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
</property>
<property name="background-image" description="This property sets the background image of an element.">
<literal-list>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="cssOffsiteUri"/>
<regexp name="cssOnsiteUri"/>
</regexp-list>
</property>
<property name="background-position" description="If a background image has been specified, this property specifies its initial position.">
<literal-list>
<literal value="top"/>
<literal value="center"/>
<literal value="bottom"/>
<literal value="left"/>
<literal value="center"/>
<literal value="right"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="percentage"/>
<regexp name="length"/>
</regexp-list>
</property>
<property name="background-repeat" description="If a background image is specified, this property specifies whether the image is repeated (tiled), and how.">
<literal-list>
<literal value="repeat"/>
<literal value="repeat-x"/>
<literal value="repeat-y"/>
<literal value="no-repeat"/>
<literal value="inherit"/>
</literal-list>
</property>
<!-- Begin simple properties -->
<property name="border-collapse" default="collapse" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="collapse"/>
<literal value="separate"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="border-color" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="transparent"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
</property>
<property name="border-top-color" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
</property>
<property name="border-right-color" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
</property>
<property name="border-bottom-color" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
</property>
<property name="border-left-color" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
</property>
<property name="bottom" default="auto" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="caption-side" default="top" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="top"/>
<literal value="bottom"/>
<literal value="left"/>
<literal value="right"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="clear" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="left"/>
<literal value="right"/>
<literal value="both"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="color" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
</property>
<property name="cue-after" default="none" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="cssOffsiteUri"/>
<regexp name="cssOnsiteUri"/>
</regexp-list>
</property>
<property name="cue-before" default="none" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="cssOffsiteUri"/>
<regexp name="cssOnsiteUri"/>
</regexp-list>
</property>
<property name="direction" default="ltr" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="ltr"/>
<literal value="rtl"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="display" default="inline" description="">
<category-list>
<category value="all"/>
</category-list>
<literal-list>
<literal value="inline"/>
<literal value="block"/>
<literal value="list-item"/>
<literal value="run-in"/>
<literal value="compact"/>
<literal value="marker"/>
<literal value="table"/>
<literal value="inline-table"/>
<literal value="table-row-group"/>
<literal value="table-header-group"/>
<literal value="table-footer-group"/>
<literal value="table-row"/>
<literal value="table-column-group"/>
<literal value="table-column"/>
<literal value="table-cell"/>
<literal value="table-caption"/>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="elevation" default="level" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="below"/>
<literal value="level"/>
<literal value="above"/>
<literal value="higher"/>
<literal value="lower"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="angle"/>
</regexp-list>
</property>
<property name="empty-cells" default="show" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="show"/>
<literal value="hide"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="float" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="left"/>
<literal value="right"/>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="font-size" default="medium" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="absolute-size"/>
<regexp name="relative-size"/>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="font-size-adjust" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="number"/>
</regexp-list>
</property>
<property name="font-stretch" default="normal" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="wider"/>
<literal value="narrower"/>
<literal value="ultra-condensed"/>
<literal value="extra-condensed"/>
<literal value="condensed"/>
<literal value="semi-condensed"/>
<literal value="semi-expanded"/>
<literal value="expanded"/>
<literal value="extra-expanded"/>
<literal value="ultra-expanded"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="font-style" default="normal" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="italic"/>
<literal value="oblique"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="font-variant" default="normal" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="small-caps"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="font-weight" default="normal" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="bold"/>
<literal value="bolder"/>
<literal value="lighter"/>
<literal value="100"/>
<literal value="200"/>
<literal value="300"/>
<literal value="400"/>
<literal value="500"/>
<literal value="600"/>
<literal value="700"/>
<literal value="800"/>
<literal value="900"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="height" default="auto" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="left" default="auto" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="letter-spacing" default="normal" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
</regexp-list>
</property>
<property name="line-height" default="normal" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="number"/>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="list-style-image" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="cssOffsiteUri"/>
<regexp name="cssOnsiteUri"/>
</regexp-list>
</property>
<property name="list-style-position" default="outside" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inside"/>
<literal value="outside"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="list-style-type" default="disc" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="disc"/>
<literal value="circle"/>
<literal value="square"/>
<literal value="decimal"/>
<literal value="decimal-leading-zero"/>
<literal value="lower-roman"/>
<literal value="upper-roman"/>
<literal value="lower-greek"/>
<literal value="lower-alpha"/>
<literal value="lower-latin"/>
<literal value="upper-alpha"/>
<literal value="upper-latin"/>
<literal value="hebrew"/>
<literal value="armenian"/>
<literal value="georgian"/>
<literal value="cjk-ideographic"/>
<literal value="hiragana"/>
<literal value="katakana"/>
<literal value="hiragana-iroha"/>
<literal value="katakana-iroha"/>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="marker-offset" default="auto" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
</regexp-list>
</property>
<property name="max-height" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="max-width" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="min-height" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="min-width" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="orphans" default="2" description="">
<category-list>
<category value="visual"/>
<category value="paged"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="integer"/>
</regexp-list>
</property>
<property name="outline-color" default="invert" description="">
<category-list>
<category value="visual"/>
<category value="interactive"/>
</category-list>
<literal-list>
<literal value="invert"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
</property>
<property name="overflow" default="visible" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="visible"/>
<literal value="hidden"/>
<literal value="scroll"/>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="page-break-after" default="auto" description="">
<category-list>
<category value="visual"/>
<category value="paged"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="always"/>
<literal value="avoid"/>
<literal value="left"/>
<literal value="right"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="page-break-before" default="auto" description="">
<category-list>
<category value="visual"/>
<category value="paged"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="always"/>
<literal value="avoid"/>
<literal value="left"/>
<literal value="right"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="page-break-inside" default="auto" description="">
<category-list>
<category value="visual"/>
<category value="paged"/>
</category-list>
<literal-list>
<literal value="avoid"/>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="pause-after" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="time"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="pause-before" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="time"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="pitch" default="medium" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="x-low"/>
<literal value="low"/>
<literal value="medium"/>
<literal value="high"/>
<literal value="x-high"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="frequency"/>
</regexp-list>
</property>
<property name="pitch-range" default="50" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="number"/>
</regexp-list>
</property>
<property name="position" default="static" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="static"/>
<!-- possible to perform phishing attacks with the following -->
<!--
<literal value="relative"/>
<literal value="absolute"/>
<literal value="fixed"/>
-->
<literal value="inherit"/>
</literal-list>
</property>
<property name="richness" default="50" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="number"/>
</regexp-list>
</property>
<property name="right" default="auto" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="size" default="auto" description="">
<category-list>
<category value="visual"/>
<category value="paged"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="portrait"/>
<literal value="landscape"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
</regexp-list>
</property>
<property name="speak" default="normal" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="none"/>
<literal value="spell-out"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="speak-header" default="once" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="once"/>
<literal value="always"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="speak-numeral" default="continuous" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="digits"/>
<literal value="continuous"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="speak-punctuation" default="none" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="code"/>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="speech-rate" default="medium" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="x-slow"/>
<literal value="slow"/>
<literal value="medium"/>
<literal value="fast"/>
<literal value="x-fast"/>
<literal value="faster"/>
<literal value="slower"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="number"/>
</regexp-list>
</property>
<property name="stress" default="50" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="number"/>
</regexp-list>
</property>
<property name="table-layout" default="auto" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="fixed"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="text-indent" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="text-transform" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="capitalize"/>
<literal value="uppercase"/>
<literal value="lowercase"/>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="top" default="auto" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="unicode-bidi" default="normal" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="embed"/>
<literal value="bidi-override"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="vertical-align" default="baseline" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="baseline"/>
<literal value="sub"/>
<literal value="super"/>
<literal value="top"/>
<literal value="text-top"/>
<literal value="middle"/>
<literal value="bottom"/>
<literal value="text-bottom"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="percentage"/>
<regexp name="length"/>
</regexp-list>
</property>
<property name="visibility" default="inherit" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="visible"/>
<literal value="hidden"/>
<literal value="collapse"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="volume" default="medium" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="silent"/>
<literal value="x-soft"/>
<literal value="soft"/>
<literal value="medium"/>
<literal value="loud"/>
<literal value="x-loud"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="number"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="white-space" default="normal" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="pre"/>
<literal value="nowrap"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="widows" default="2" description="">
<category-list>
<category value="visual"/>
<category value="paged"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="integer"/>
</regexp-list>
</property>
<property name="width" default="auto" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="word-spacing" default="normal" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="normal"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
</regexp-list>
</property>
<!-- end simple properties -->
<!-- begin medium properties -->
<property name="border-style" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
<literal value="none"/>
<literal value="hidden"/>
<literal value="dotted"/>
<literal value="dashed"/>
<literal value="solid"/>
<literal value="double"/>
<literal value="groove"/>
<literal value="ridge"/>
<literal value="inset"/>
<literal value="outset"/>
</literal-list>
</property>
<property name="border-top-style" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
</property>
<property name="border-right-style" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="border-style"/>
</shorthand-list>
</property>
<property name="border-bottom-style" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="border-style"/>
</shorthand-list>
</property>
<property name="border-left-style" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="border-style"/>
</shorthand-list>
</property>
<property name="border-top-width" default="medium" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="border-width"/>
</shorthand-list>
</property>
<property name="border-right-width" default="medium" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="border-width"/>
</shorthand-list>
</property>
<property name="border-bottom-width" default="medium" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="border-width"/>
</shorthand-list>
</property>
<property name="border-left-width" default="medium" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="border-width"/>
</shorthand-list>
</property>
<property name="border-width" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
<literal value="thin"/>
<literal value="medium"/>
<literal value="thick"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
</regexp-list>
</property>
<property name="margin" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
<literal value="auto"/>
</literal-list>
<regexp-list>
<regexp name="positiveLength"/>
<regexp name="positivePercentage"/>
</regexp-list>
</property>
<property name="margin-top" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="margin"/>
</shorthand-list>
</property>
<property name="margin-right" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="margin"/>
</shorthand-list>
</property>
<property name="margin-bottom" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="margin"/>
</shorthand-list>
</property>
<property name="margin-left" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="margin"/>
</shorthand-list>
</property>
<property name="outline-style" default="none" description="">
<category-list>
<category value="visual"/>
<category value="interactive"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="border-style"/>
</shorthand-list>
</property>
<property name="outline-width" default="medium" description="">
<category-list>
<category value="visual"/>
<category value="interactive"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="border-width"/>
</shorthand-list>
</property>
<property name="padding" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="padding-top" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="padding"/>
</shorthand-list>
</property>
<property name="padding-right" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="padding"/>
</shorthand-list>
</property>
<property name="padding-bottom" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="padding"/>
</shorthand-list>
</property>
<property name="padding-left" default="0" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="padding"/>
</shorthand-list>
</property>
<!-- end medium properties -->
<!-- begin hard properties -->
<property name="border" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
<shorthand-list>
<shorthand name="border-width"/>
<shorthand name="border-style"/>
</shorthand-list>
</property>
<property name="border-top" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
<shorthand-list>
<shorthand name="border-top-width"/>
<shorthand name="border-style"/>
</shorthand-list>
</property>
<property name="border-right" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
<shorthand-list>
<shorthand name="border-top-width"/>
<shorthand name="border-style"/>
</shorthand-list>
</property>
<property name="border-bottom" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
<shorthand-list>
<shorthand name="border-top-width"/>
<shorthand name="border-style"/>
</shorthand-list>
</property>
<property name="border-left" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
</regexp-list>
<shorthand-list>
<shorthand name="border-top-width"/>
<shorthand name="border-style"/>
</shorthand-list>
</property>
<property name="cue" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="cue-before"/>
<shorthand name="cue-after"/>
</shorthand-list>
</property>
<property name="list-style" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="list-style-type"/>
<shorthand name="list-style-position"/>
<shorthand name="list-style-image"/>
</shorthand-list>
</property>
<property name="marks" default="none" description="">
<category-list>
<category value="visual"/>
<category value="paged"/>
</category-list>
<literal-list>
<literal value="crop"/>
<literal value="cross"/>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="outline" description="">
<category-list>
<category value="visual"/>
<category value="interactive"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="outline-color"/>
<shorthand name="outline-style"/>
<shorthand name="outline-width"/>
</shorthand-list>
</property>
<property name="pause" description="">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="time"/>
<regexp name="percentage"/>
</regexp-list>
</property>
<property name="text-decoration" default="none" description="">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="underline"/>
<literal value="overline"/>
<literal value="line-through"/>
<literal value="blink"/>
<literal value="inherit"/>
</literal-list>
</property>
<!-- end hard properties -->
<!-- begin manual properties -->
<property name="border-spacing" default="0" description="The lengths specify the distance that separates adjacent cell borders. If one length is specified, it gives both the horizontal and vertical spacing. If two are specified, the first gives the horizontal spacing and the second the vertical spacing. Lengths may not be negative.">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
</regexp-list>
</property>
<property name="clip" default="auto" description="The 'clip' property applies to elements that have a 'overflow' property with a value other than 'visible'.">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="length"/>
</regexp-list>
</property>
<property name="counter-increment" default="none" description="The 'counter-increment' property accepts one or more names of counters (identifiers), each one optionally followed by an integer.">
<category-list>
<category value="all"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="cssIdentifier"/>
<regexp name="integer"/>
</regexp-list>
</property>
<property name="cursor" default="auto" description="This property specifies the type of cursor to be displayed for the pointing device.">
<category-list>
<category value="visual"/>
<category value="interactive"/>
</category-list>
<literal-list>
<literal value="auto"/>
<literal value="inherit"/>
<literal value="crosshair"/>
<literal value="default"/>
<literal value="pointer"/>
<literal value="move"/>
<literal value="e-resize"/>
<literal value="ne-resize"/>
<literal value="nw-resize"/>
<literal value="n-resize"/>
<literal value="se-resize"/>
<literal value="sw-resize"/>
<literal value="s-resize"/>
<literal value="w-resize| text"/>
<literal value="wait"/>
<literal value="help"/>
</literal-list>
<regexp-list>
<regexp name="cssOffsiteUri"/>
<regexp name="cssOnsiteUri"/>
</regexp-list>
</property>
<property name="text-shadow" default="none" description="This property accepts a comma-separated list of shadow effects to be applied to the text of the element.">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="none"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="colorName"/>
<regexp name="colorCode"/>
<regexp name="rgbCode"/>
<regexp name="systemColor"/>
<regexp name="length"/>
</regexp-list>
</property>
<property name="font" description="The 'font' property is, except as described below, a shorthand property for setting 'font-style', 'font-variant', 'font-weight', 'font-size', 'line-height', and 'font-family', at the same place in the style sheet.">
<category-list>
<category value="visual"/>
</category-list>
<literal-list>
<literal value="/"/>
<literal value="caption"/>
<literal value="icon"/>
<literal value="menu"/>
<literal value="message-box"/>
<literal value="small-caption"/>
<literal value="status-bar"/>
<literal value="inherit"/>
</literal-list>
<shorthand-list>
<shorthand name="font-style"/>
<shorthand name="font-variant"/>
<shorthand name="font-weight"/>
<shorthand name="font-size"/>
<shorthand name="line-height"/>
<shorthand name="font-family"/>
</shorthand-list>
</property>
<property name="font-family" description="This property specifies a prioritized list of font family names and/or generic family names.">
<category-list>
<category value="visual"/>
</category-list>
<!-- allowing only generic font families -->
<literal-list>
<literal value="serif"/>
<literal value="arial"/>
<literal value="lucida console"/>
<literal value="sans-serif"/>
<literal value="cursive"/>
<literal value="verdana"/>
<literal value="fantasy"/>
<literal value="monospace"/>
</literal-list>
<regexp-list>
<regexp value="[\w,\-&apos;&quot; ]+"/>
</regexp-list>
</property>
<property name="page" description="The 'page' property can be used to specify a particular type of page where an element should be displayed.">
<category-list>
<category value="visual"/>
<category value="paged"/>
</category-list>
<literal-list>
<literal value="auto"/>
</literal-list>
<regexp-list>
<regexp name="cssIdentifier"/>
</regexp-list>
</property>
<property name="play-during" default="auto" description="Similar to the 'cue-before' and 'cue-after' properties, this property specifies a sound to be played as a background while an element's content is spoken.">
<category-list>
<category value="aural"/>
</category-list>
<literal-list>
<literal value="mix"/>
<literal value="repeat"/>
<literal value="none"/>
<literal value="auto"/>
<literal value="inherit"/>
</literal-list>
<regexp-list>
<regexp name="cssOffsiteUri"/>
<regexp name="cssOnsiteUri"/>
</regexp-list>
</property>
<property name="text-align" description="This property describes how inline content of a block is aligned.">
<category-list>
<category value="visual"/>
</category-list>
<!-- For safety, ignoring string alignment which can be used to line table cells on characters -->
<literal-list>
<literal value="left"/>
<literal value="right"/>
<literal value="center"/>
<literal value="justify"/>
<literal value="inherit"/>
</literal-list>
</property>
<property name="voice-family" description="The value is a comma-separated, prioritized list of voice family names (compare with 'font-family').">
<category-list>
<category value="aural"/>
</category-list>
<!-- Allowing only generic voice family -->
<literal-list>
<literal value="male"/>
<literal value="female"/>
<literal value="child"/>
<literal value="inherit"/>
</literal-list>
</property>
<!-- end manual properties -->
</css-rules>
<allowed-empty-tags>
<literal-list>
<literal value="br"/>
<literal value="hr"/>
<literal value="a"/>
<literal value="img"/>
<literal value="link"/>
<literal value="iframe"/>
<literal value="script"/>
<literal value="object"/>
<literal value="applet"/>
<literal value="frame"/>
<literal value="base"/>
<literal value="param"/>
<literal value="meta"/>
<literal value="input"/>
<literal value="textarea"/>
<literal value="embed"/>
<literal value="basefont"/>
<literal value="col"/>
<literal value="div"/>
</literal-list>
</allowed-empty-tags>
</anti-samy-rules>
...@@ -70,7 +70,6 @@ Slashdot allowed tags taken from "Reply" page: ...@@ -70,7 +70,6 @@ Slashdot allowed tags taken from "Reply" page:
<attribute name="href" onInvalid="filterTag"> <attribute name="href" onInvalid="filterTag">
<regexp-list> <regexp-list>
<regexp name="onsiteURL"/> <regexp name="onsiteURL"/>
<regexp name="offsiteURL"/>
</regexp-list> </regexp-list>
</attribute> </attribute>
......
...@@ -8,9 +8,12 @@ spring: ...@@ -8,9 +8,12 @@ spring:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/iot_license?serverTimezone=GMT%2B8 url: jdbc:mysql://localhost:3306/iot_license?serverTimezone=GMT%2B8
username: root username: root
password: 123456 password: ENC(F0TJ9iT6D4VW8xVjZif9Nqw==)
mybatis-plus: mybatis-plus:
mapper-locations: classpath:/mapper/**.xml mapper-locations: classpath:/mapper/**.xml
type-aliases-package: iot.sixiang.license.entity type-aliases-package: iot.sixiang.license.entity
knife4j: knife4j:
enable: true enable: true
other:
sm4-key: sixiang890123456
\ No newline at end of file
server:
port: 8868
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://rm-wz9w0x7a26q11av687o.mysql.rds.aliyuncs.com:3306/iot_license?serverTimezone=GMT%2B8
username: dada
password: Acc2019123
mybatis-plus:
mapper-locations: classpath:/mapper/**.xml
type-aliases-package: iot.sixiang.license.entity
knife4j:
enable: true
logging:
level:
root: info
\ No newline at end of file
server:
port: 8868
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://rm-wz9w0x7a26q11av687o.mysql.rds.aliyuncs.com:3306/iot_license?serverTimezone=GMT%2B8
username: dada
password: Acc2019123
main:
allow-bean-definition-overriding: true
mybatis-plus:
mapper-locations: classpath:/mapper/**.xml
type-aliases-package: iot.sixiang.license.entity
knife4j:
enable: true
logging:
level:
root: info
\ No newline at end of file
spring: spring:
profiles: profiles:
active: test active: dev
application: application:
name: iot_license #当前服务的名称 name: iot_license #当前服务的名称
main: main:
allow-bean-definition-overriding: true allow-bean-definition-overriding: true
# 这个邮箱部署的时候要改成自己公司的
mail:
host: smtp.mxhichina.com
port: 465
username: dev_team@huahuico.com
password: ENC(eUd8aq15PjmiIF1GBeRwkJJvGZKaAYKu)
# 需要配置成管理员邮箱
to: MAllk33@163.com
default-encoding: UTF-8
properties:
mail:
smtp:
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
fallback: false
## 配置输出日志 ## 配置输出日志
logging: logging:
config: classpath:logback-spring.xml config: classpath:logback-spring.xml
server:
tomcat:
port-header: HEAD,PUT,DELETE,OPTIONS,TRACE,COPY,SEARCH,PROPFIND
cros:
# 需要设置访问白名单
cros_allowed_origins: http://192.168.1.88:8080, http://192.168.1.88:8081, http://localhost:8868, http://localhost:8080, http://192.168.1.54:8080
cros_allowed_method: GET,POST
other:
md5:
salt: PI7dBYlEfeP8IZ6vogqFL1U5pVnyCuNAGja3lsREx4M9r0SX
error_count:
change_pwd: 5 # 修改密码的最大错误次数
forget_pwd: 5 # 忘记密码的最大错误次数
check_code: 5 # 校验验证码的最大错误次数
code_exp_time: 3 # 验证码失效时间,单位:分钟
rsa:
public_key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA18W2H1hO98dUWf1PNKNWTWmxCyvvy0NOR7iSvp76J0LdzyMJxs8WHVAmRfSGOb9SvpDZhBVx11bhTBqkl1qMzJWzn+F2ZtTCH2nXZcJHwSfLuGqin5FRBYW1WrFkqwg+R80aOuRSrbo0k1bZg3JPkkCxISHieEZPjSV5a4r7+Xopj0a9Dnh3rh4nDmH2p/wvotkx1oMKdhFglYcAITlk9ucEUf+CDuSdTAFFeKg9+fPqwKqWZRJZPQXqV3pGZ1/JS7gPnBFGZojW44eJufkBeiW3pbBvm/cKOkTnb8o4oltYUJsirYSQCCG+sDtxUAuGxuDCv8p+r8dWE1z5+xKclQIDAQAB
private_key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDXxbYfWE73x1RZ/U80o1ZNabELK+/LQ05HuJK+nvonQt3PIwnGzxYdUCZF9IY5v1K+kNmEFXHXVuFMGqSXWozMlbOf4XZm1MIfaddlwkfBJ8u4aqKfkVEFhbVasWSrCD5HzRo65FKtujSTVtmDck+SQLEhIeJ4Rk+NJXlrivv5eimPRr0OeHeuHicOYfan/C+i2THWgwp2EWCVhwAhOWT25wRR/4IO5J1MAUV4qD358+rAqpZlElk9BepXekZnX8lLuA+cEUZmiNbjh4m5+QF6JbelsG+b9wo6ROdvyjiiW1hQmyKthJAIIb6wO3FQC4bG4MK/yn6vx1YTXPn7EpyVAgMBAAECggEAR7YQ+kfqLtVThnj2mwLyCtZmndTjZEWhPZrtQmcpsmS5vT7i3+0xZ1qc7cD/3y9j+6u+bvSFmlDondd4/kh85P2X7joLlM9/GNufV9WC7YIhZdAi7i9ooxI2HMc6MtGRiWF0J0B87folwRYrQlF6epv/goh1cQ3FIJ7kxMYzSk0gF0JcmOZn3KH8tMt3t/GK+uVUIycuEQQKsaTTq45nIM7oqhlAwD/M+IO2pGFkLXJ23FzFACI10qBdpn+xL2xFGRO6EE8EAeDslT4OvvN3/vtnSnRNn8CJqfoEG40XO0xrZzH1noI35iPWX1WrN7qFLAhl2oLhu1ZSIA1tz0+I/QKBgQD3X/islXfVmV2XeuHvaf4qcMAdrgLQwtmLlHhFxfFURPh6au8uatDgUA8HWcRACmhtTruytlFRGKKFwZxuQE/LOZh67Uts3GTs5eHN8xvZTL+en+n7B/cCRYrrg3+yAM/k0eezIlk65iW700o+icEHxkwTXhhVBmIROBzpXsVCwwKBgQDfS6kVhgZxLMQePbXUQ1NBr2KbfhXLzceINhsoyWLa1rIk8+9HLSxw8q0zma12Jqkd22OAgkbeLDy+niYPi3pUrWAm8O59Ot1aaOarxMTvEv7+eS+urKId57sli/hQTWsS+xghA4+VfW2+EY++pYyZIp+j+1/Q2ciXWVJy4iv9xwKBgFzW8+kxn2vWxz1WrPzBdtZOwothB0V6G1M7QXhONag+ylKHV4TAKexFn55Onky6mz6K0f7cVeBtsnEonKD0Gf5Xe1aHQEt225ndHMXCe60uFKxfr9y6vIVpvB1vmLkhfOSPsrmUJpDoVzkKr06RPJTCY0LRiag/YQa9XHxpSPcpAoGAKbsiJnudyJjtLhmqWbkbXjNA4n515FjY6YPzH3RDnVJyiKVuGoc+vv0bkYEvAd3HzWSq++FdDTiHQbictFsEyb59McnlSFIv/C2Orptfkq6iKTzMxIBO6/fa6fF2vss5L5rtr33S38VJNTRjAOY/mH74BtV72rRY4LA40G+keRECgYEAiGg0DYxcSGf2bEP1WESYPTTdgS5ke1niIwZ00SgtkIjPSVgTCmf4Tciys6lGSe/Oqnvk24VR6pz07wzcbH92AURVaeqiEvVuVonzA6Yl0jxeOIM31S1BSBJRT8kDijuvwoJu2tPoZG0306KF9L8pyy1Z6cTTmIfGR0NpZCHWPSg=
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" scanPeriod="10 seconds">
<!-- <logger>用来设置某一个包或者具体的某一个类的日志打印级别、 -->
<!-- <logger name="iot.sixiang.license" level="debug" />-->
<!--控制台输出的格式设置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 控制台输出的日志 的格式 -->
<encoder>
<pattern>
%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger{96}:%line - %msg%n
</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 只是DEBUG级别以上的日志才显示 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>
<!--文件输出的格式设置 -->
<appender name="ALL_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志日常打印文件 -->
<file>logs/license.log</file>
<!-- 配置日志所生成的目录以及生成文件名的规则 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/license.log-%d{yyyy-MM-dd}.%i</fileNamePattern>
<!-- 如果按天来回滚,则最大保存时间为365天,365天之前的都将被清理掉 -->
<maxHistory>365</maxHistory>
<!-- 日志总保存量为10GB -->
<totalSizeCap>100GB</totalSizeCap>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!--文件达到 最大128MB时会被压缩和切割 -->
<maxFileSize>40 MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<!-- 文件输出的日志 的格式 -->
<encoder>
<pattern>
%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger{96}:%line - %msg%n
</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- Safely log to the same file from multiple JVMs. Degrades performance! -->
<prudent>false</prudent>
</appender>
<!--文件输出的格式设置 -->
<appender name="MSG_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志日常打印文件 -->
<file>logs/message.log</file>
<!-- 配置日志所生成的目录以及生成文件名的规则 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/message.log-%d{yyyy-MM-dd}.%i</fileNamePattern>
<!-- 如果按天来回滚,则最大保存时间为365天,365天之前的都将被清理掉 -->
<maxHistory>365</maxHistory>
<!-- 日志总保存量为10GB -->
<totalSizeCap>100GB</totalSizeCap>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!--文件达到 最大128MB时会被压缩和切割 -->
<maxFileSize>40 MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 此日志文档只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 文件输出的日志 的格式 -->
<encoder>
<pattern>
%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger{96}:%line - %msg%n
</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- Safely log to the same file from multiple JVMs. Degrades performance! -->
<prudent>false</prudent>
</appender>
<!-- Enable FILE and STDOUT appenders for all log messages. By default,
only log at level INFO and above. -->
<!--这里选择INFO就代表,进行INFO级别输出记录,那么在控制台也好,log文件也好只记录INFO及以上级别的日志,这里相当于第一道设置-->
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="ALL_FILE" />
<appender-ref ref="MSG_FILE" />
</root>
</configuration>
\ No newline at end of file
...@@ -7,14 +7,11 @@ ...@@ -7,14 +7,11 @@
<if test="null != sn and '' != sn"> <if test="null != sn and '' != sn">
and sn like concat('%',#{sn},'%') and sn like concat('%',#{sn},'%')
</if> </if>
<if test="null != status"> <if test="null != status and status == 0">
and status = #{status} and status = #{status}
</if> </if>
<if test="startTime != null and startTime != ''"> <if test="null != status and status == 1">
AND create_time &gt; #{startTime} and (status = #{status} or status is null)
</if>
<if test="endTime != null and endTime != ''">
AND create_time &lt; #{endTime}
</if> </if>
and deleted = 0 and deleted = 0
order by create_time desc order by create_time desc
......
...@@ -5,14 +5,7 @@ ...@@ -5,14 +5,7 @@
insert into sys_oper_log(title, business_type, uri, status, opt_param, error_msg, oper_time) values (#{title},#{businessType},#{uri},#{status},#{optParam},#{errorMsg},#{operTime}) insert into sys_oper_log(title, business_type, uri, status, opt_param, error_msg, oper_time) values (#{title},#{businessType},#{uri},#{status},#{optParam},#{errorMsg},#{operTime})
</insert> </insert>
<select id="getOperLogList" resultType="iot.sixiang.license.entity.SysOperLog"> <select id="getOperLogList" resultType="iot.sixiang.license.model.vo.SysOperLogVo">
select id, title, business_type, uri, status, opt_param, error_msg, oper_time from sys_oper_log select id, title, business_type, uri, status, error_msg, oper_time from sys_oper_log order by oper_time desc
where 1=1
<if test="startTime != null and startTime != ''">
AND oper_time &gt; #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND oper_time &lt; #{endTime}
</if>
</select> </select>
</mapper> </mapper>
...@@ -35,7 +35,11 @@ ...@@ -35,7 +35,11 @@
</select> </select>
<select id="getUserByUserName" resultType="iot.sixiang.license.entity.User"> <select id="getUserByUserName" resultType="iot.sixiang.license.entity.User">
select user_id from user where user_name = #{userName} select * from user where user_name = #{userName}
</select>
<select id="getUserById" resultType="iot.sixiang.license.entity.User">
select * from user where user_id = #{userId}
</select> </select>
</mapper> </mapper>
package iot.sixiang.license;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
/**
* Created by M=54G
* Date 9/14/22 3:08 PM
* Description
*/
@SpringBootTest
@ActiveProfiles({"test-acc"})
@Slf4j
public class BaseTest {
protected void log(Object object) {
log.info(JSON.toJSONString(object));
}
}
\ No newline at end of file
package iot.sixiang.license.controller;
import com.alibaba.fastjson2.JSON;
import iot.sixiang.license.object.data.AuthData;
import iot.sixiang.license.util.HmacUtil;
import iot.sixiang.license.util.sm4.SM4;
import iot.sixiang.license.util.sm4.SM4Context;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Random;
/**
* Created by M=54G
* Date 11/11/22 9:54 AM
* Description
*/
public class DeviceControllerTest {
@Test
void terminalDeviceSign() {
String appId = "7j26zr7en9fiyoyvjz";
String sn = "8HOE8JH4EFSEV28534";
// String snBind = "snabcd";
String appKey = "2";
String string = "app_id=" + appId + "&sn=" + sn;
String sign = HmacUtil.encrypt(string, appKey, HmacUtil.HMAC_SHA1);
System.out.println("token appId:" + appId);
System.out.println("token sn:" + sn);
System.out.println("token sign:" + sign);
}
@Test
void tokenSign() {
String appId = "ebsh71dp5t1ck948l5";
String sn = "ERE54S619LNYMPKVN9";
String snBind = "snabcd";
String appKey = "110801";
String string = "app_id=" + appId + "&sn=" + sn + "&sn_bind=" + snBind;
String sign = HmacUtil.encrypt(string, appKey, HmacUtil.HMAC_SHA1);
System.out.println("token appId:" + appId);
System.out.println("token sn:" + sn);
System.out.println("token sign:" + sign);
}
@Test
void auth() {
String appId = "ebsh71dp5t1ck948l5";
String sn = "ERE54S619LNYMPKVN9";
String snBind = "snabcd";
String appKey = "110801";
//byte[] baseKeyBytes = "nAOq38p4bGQyF4FG".getBytes();
//System.out.println(baseKeyBytes.length);
byte[] allBytes = getAuthSendBytes(appId, sn, snBind, appKey);
System.out.println(bytes2Hex(allBytes));
}
@Test
void testSocket() {
String serverIp = "112.74.57.111";
int serverPort = 18889;
String appId = "ebsh71dp5t1ck948l5";
String sn = "ERE54S619LNYMPKVN9";
String snBind = "ZA2207G5NQ";
String appKey = "110801";
socket(serverIp, serverPort, appId, sn, snBind, appKey);
}
@Test
void yxSocket() {
String serverIp = "14.116.221.61";
int serverPort = 18889;
String appId = "mny3i9pgg0xxs520qf";
String sn = "IU23404BR1CQJOC63Q";
String snBind = "snabcd";
String appKey = "20221114";
socket(serverIp, serverPort, appId, sn, snBind, appKey);
}
@SneakyThrows
void socket(String serverIp, int serverPort, String appId, String sn, String snBind, String appKey) {
Socket socket = new Socket(serverIp, serverPort);
socket.setKeepAlive(true);
System.out.println("connect success...");
// 事先组装好要发送的鉴权信息
byte[] authSendBytes = getAuthSendBytes(appId, sn, snBind, appKey);
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
// 鉴权
sendAndReceive(socket, outputStream, inputStream, "auth", authSendBytes);
Thread.sleep(1000);
// 鉴权后做动作
String request = "55AA340090000156F43D4D806827D1BB8F78C00D2B5488479CEB172C5D477C4D3023CE7B111621D4AD2C11ACAC4D876A3AC66A82F5F19000EF";
byte[] actionSendBytes = hex2Byte(request);
byte[] actionResultBytes = sendAndReceive(socket, outputStream, inputStream, "action", actionSendBytes);
//String result = "55AA1500A40035414E7DB5B3EDE72BC6BA44203F52EA0000005B";
//String result = "55aa1500a4008926834e684c4c6911b02304b3a0ce9c00000000";
//Assert.assertEquals(bytes2Hex(actionResultBytes), result);
inputStream.close();
outputStream.close();
socket.close();
}
@SneakyThrows
private byte[] sendAndReceive(Socket socket, OutputStream outputStream, InputStream inputStream, String tag, byte[] requestBytes) {
System.out.println(tag + " send:" + bytes2Hex(requestBytes));
outputStream.write(requestBytes);
outputStream.flush();
byte[] bytes = new byte[1024];
int count = inputStream.read(bytes);
while (count < 0) {
Thread.sleep(200);
count = inputStream.read(bytes);
}
byte[] resultBytes = new byte[count];
for (int i = 0; i < count; i++) {
resultBytes[i] = bytes[i];
}
System.out.println(tag + " receive:" + bytes2Hex(resultBytes));
return requestBytes;
}
private byte[] getAuthSendBytes(String appId, String sn, String snBind, String appKey) {
byte[] stxBytes = {(byte) 0x55, (byte) 0xaa};
// 这部分生成内容
// 用于SM4
byte[] randomBytes = new byte[16];
Random random = new Random();
for (int i = 0; i < randomBytes.length; i++) {
randomBytes[i] = (byte) (random.nextInt());
}
byte[] sm4KeyBytes = new byte[16];
byte[] baseKeyBytes = "nAOq38p4bGQyF4FG".getBytes();
for (int i = 0; i < randomBytes.length; i++) {
sm4KeyBytes[i] = (byte) (randomBytes[i] ^ baseKeyBytes[i]);
}
String string = "app_id=" + appId + "&sn=" + sn + "&sn_bind=" + snBind;
String sign = HmacUtil.encrypt(string, appKey, HmacUtil.HMAC_SHA1);
// 组装
AuthData authData = new AuthData();
authData.setApp_id(appId);
authData.setSn(sn);
authData.setSign(sign);
byte[] dataBytes = encryptData_ECB(JSON.toJSONString(authData), sm4KeyBytes);
dataBytes = byteMerger(randomBytes, dataBytes);
int length = dataBytes.length + stxBytes.length;
byte[] lenBytes = {(byte) length, (byte) (length >> 8)};
// 这部分是命令
byte cmdByte = (byte) 0x01;
byte ackByte = (byte) 0x00;
// 结束符
byte endByte = (byte) 0x00;
// 加密最后字段
endByte = (byte) (endByte ^ cmdByte);
endByte = (byte) (endByte ^ ackByte);
for (int i = 0; i < length - 2; i++) {
endByte = (byte) (endByte ^ dataBytes[i]);
}
return byteMerger(stxBytes, lenBytes, new byte[]{cmdByte, ackByte}, dataBytes, new byte[]{endByte});
}
public byte[] encryptData_ECB(String string, byte[] keyBytes) {
try {
SM4Context ctx = new SM4Context();
ctx.mode = SM4.SM4_ENCRYPT;
SM4 sm4 = new SM4();
sm4.sm4_setkey_enc(ctx, keyBytes);
byte[] encrypted = sm4_crypt_ecb(sm4, ctx, string.getBytes("UTF-8"));
return encrypted;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public byte[] sm4_crypt_ecb(SM4 sm4, SM4Context ctx, byte[] input) throws Exception {
int length = input.length;
ByteArrayInputStream bins = new ByteArrayInputStream(input);
ByteArrayOutputStream bous = new ByteArrayOutputStream();
for (; length > 0; length -= 16) {
byte[] in = new byte[16];
byte[] out = new byte[16];
bins.read(in);
sm4.sm4_one_round(ctx.sk, in, out);
bous.write(out);
}
byte[] output = bous.toByteArray();
bins.close();
bous.close();
return output;
}
@Test
void authDevice() {
}
public static byte[] byteMerger(byte[]... byteList) {
int lengthByte = 0;
for (int i = 0; i < byteList.length; i++) {
lengthByte += byteList[i].length;
}
byte[] allByte = new byte[lengthByte];
int countLength = 0;
for (int i = 0; i < byteList.length; i++) {
byte[] b = byteList[i];
System.arraycopy(b, 0, allByte, countLength, b.length);
countLength += b.length;
}
return allByte;
}
public static String bytes2Hex(byte[] bytes) {
if (bytes == null) {
return null;
}
StringBuilder builder = new StringBuilder();
// 遍历byte[]数组,将每个byte数字转换成16进制字符,再拼接起来成字符串
for (int i = 0; i < bytes.length; i++) {
// 每个byte转换成16进制字符时,bytes[i] & 0xff如果高位是0,输出将会去掉,所以+0x100(在更高位加1),再截取后两位字符
builder.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
return builder.toString();
}
public static byte[] hex2Byte(String string) {
if (string == null || string.length() < 1) {
return null;
}
// 因为一个byte生成两个字符,长度对应1:2,所以byte[]数组长度是字符串长度一半
byte[] bytes = new byte[string.length() / 2];
// 遍历byte[]数组,遍历次数是字符串长度一半
for (int i = 0; i < string.length() / 2; i++) {
// 截取没两个字符的前一个,将其转为int数值
int high = Integer.parseInt(string.substring(i * 2, i * 2 + 1), 16);
// 截取没两个字符的后一个,将其转为int数值
int low = Integer.parseInt(string.substring(i * 2 + 1, i * 2 + 2), 16);
// 高位字符对应的int值*16+低位的int值,强转成byte数值即可
// 如dd,高位13*16+低位13=221(强转成byte二进制11011101,对应十进制-35)
bytes[i] = (byte) (high * 16 + low);
}
return bytes;
}
//public static void main(String[] args) {
// byte[] stxbyte = {(byte) 0x7E};
// byte[] typebyte = {(byte) 0x01};
// RespDevDataDto build = RespDevDataDto.builder().seqNo("0")
// .deviceSn("FSDF32FFZV").command("decodeconnectnorth")
// .timeStamp("1652233401604")
// .data(toStringHex("55AA34009000AB752BE54B0B05796E4C5E60060D99B79A37A534B4D081A6184C105FD7EABDBFE5ECE7EF08F933ED415CCD6DA82157059000FE")).build();
// String serverRespSign = DecodeHmacShaUtils.terminalReqSign(build);
// build.setSign(serverRespSign);
// byte[] resultbyte = JSONProvider.toJSONString(build).getBytes();
// Integer len = resultbyte.length + typebyte.length;
// String strlen = Integer.toString(len, 16);
// byte[] lenbyte = ByteHelper.hexStrToBytes(strlen, 2);
// byte[] databyte = ByteHelper.byteMerger(stxbyte, lenbyte, typebyte, resultbyte);
// System.out.println(byte2Hex(databyte));
// //7e0100017b22636f6d6d616e64223a226465636f6465636f6e6e6563746e6f727468222c2264617461223a2255efbfbd345c7530303030efbfbd5c7530303030efbfbd752befbfbd4b5c75303030425c7530303035796e4c5e605c75303030365c72efbfbdefbfbdefbfbd37efbfbd34efbfbdd081efbfbd5c75303031384c5c75303031305fefbfbdeabdbfefbfbdefbfbdefbfbdefbfbd5c62efbfbd33efbfbd415c5cefbfbd6defbfbd21575c7530303035efbfbd5c7530303030efbfbd222c22646576696365536e223a2246534446333246465a56222c227365714e6f223a2230222c227369676e223a2244344245393930333539343346454331323345354132414534443145353231304236413541463635222c2274696d655374616d70223a2231363532323333343031363034227d
//}
// 转化十六进制编码为字符串
//public static String toStringHex(String s) {
// byte[] baKeyword = new byte[s.length() / 2];
// for (int i = 0; i < baKeyword.length; i++) {
// try {
// baKeyword[i] = (byte) Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// try {
// s = new String(baKeyword, "utf-8");//UTF-16le:Not
// } catch (Exception e1) {
// e1.printStackTrace();
// }
// return s;
//}
//public static String bytes2hex(byte[] bytes) {
// StringBuilder sb = new StringBuilder();
// String tmp;
// sb.append("[");
// for (byte b : bytes) {
// // 将每个字节与0xFF进行与运算,然后转化为10进制,然后借助于Integer再转化为16进制
// //tmp = Integer.toHexString(b);
// tmp = Integer.toString((b & 0xff) + 0x100, 16).substring(1);
// if (tmp.length() == 1) {
// tmp = "0" + tmp;//只有一位的前面补个0
// }
// sb.append(tmp).append(",");//每个字节用空格断开
// }
// sb.delete(sb.length() - 1, sb.length());//删除最后一个字节后面对于的空格
// sb.append("]");
// return sb.toString();
//}
}
\ No newline at end of file
package iot.sixiang.license.object.data;
import lombok.Data;
/**
* Created by M=54G
* Date 11/11/22 10:08 AM
* Description
*/
@Data
public class AuthData {
private String app_id;
private String sn;
private String sign;
}
\ No newline at end of file
package iot.sixiang.license.service;
import iot.sixiang.license.BaseTest;
import org.junit.jupiter.api.Test;
import javax.annotation.Resource;
/**
* Created by M=54G
* Date 11/23/22 3:39 PM
* Description
*/
public class PmsUseServiceTest extends BaseTest {
@Resource
private PmsUseService pmsUseService;
@Test
void addLog() {
log(pmsUseService.createUseLog("abcd"));
}
@Test
void updateLog() {
pmsUseService.success(1);
}
}
\ No newline at end of file
package iot.sixiang.license.util;
import org.apache.http.util.TextUtils;
public class ByteHelper {
/**
* src:源数组
* srcPos:源数组要复制的起始位置
* dest:目的数组
* destPos:目的数组放置的起始位置
* length:要复制的长度
*
* @param src
* @param begin
* @param count
* @return
*/
public static byte[] subBytes(byte[] src, int begin, int count) {
byte[] bs = new byte[count];
System.arraycopy(src, begin, bs, 0, count);
return bs;
}
/**
* 字节码转化十六进制
*
* @author xzb
*/
public static String fromBytesToHex(byte[] resultBytes) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < resultBytes.length; i++) {
if (Integer.toHexString(0xFF & resultBytes[i]).length() == 1) {
builder.append("0").append(Integer.toHexString(0xFF & resultBytes[i]));
} else {
builder.append(Integer.toHexString(0xFF & resultBytes[i]));
}
}
return builder.toString();
}
/**
* byte[] 转为16进制String
*/
public static String Bytes2HexString(byte[] b) {
String ret = "";
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
}
return ret;
}
/**
* 转化十六进制编码为字符串
*
* @param s
* @return
*/
public static String toStringHex(String s) {
byte[] baKeyword = new byte[s.length() / 2];
for (int i = 0; i < baKeyword.length; i++) {
try {
baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
} catch (Exception e) {
e.printStackTrace();
}
}
try {
s = new String(baKeyword, "utf-8");//UTF-16le:Not
} catch (Exception e1) {
e1.printStackTrace();
}
return s;
}
/***
* 合并数组
* @param byteList
* @return
*/
public static byte[] byteMerger(byte[]... byteList) {
int lengthByte = 0;
for (int i = 0; i < byteList.length; i++) {
lengthByte += byteList[i].length;
}
byte[] allByte = new byte[lengthByte];
int countLength = 0;
for (int i = 0; i < byteList.length; i++) {
byte[] b = byteList[i];
System.arraycopy(b, 0, allByte, countLength, b.length);
countLength += b.length;
}
return allByte;
}
/**
* 字符串转16进制
*
* @param string
* @return
*/
public static String stringToHexString(String string) {
char[] c = new char[string.length()];
c = string.toCharArray();
String hesStr = "";
for (int i = 0; i < c.length; i++) {
hesStr = hesStr + Integer.toHexString(c[i]);
}
return hesStr;
}
/**
* 字符串转化成为16进制字符串
*
* @param s
* @return
*/
public static String strTo16(String s) {
String str = "";
for (int i = 0; i < s.length(); i++) {
int ch = (int) s.charAt(i);
String s4 = Integer.toHexString(ch);
str = str + s4;
}
return str;
}
/**
* hex字符串转byte数组
*
* @param inHex 待转换的Hex字符串
* @return 转换后的byte数组结果
*/
public static byte[] hexToByteArray(String inHex, int len) {
int hexlen = inHex.length();
byte[] result;
if (hexlen % 2 == 1) {
//奇数
hexlen++;
result = new byte[(hexlen / 2)];
inHex = "0" + inHex;
} else {
//偶数
result = new byte[(hexlen / 2)];
}
int j = 0;
for (int i = 0; i < hexlen; i += 2) {
result[j] = hexToByte(inHex.substring(i, i + 2));
j++;
}
return result;
}
public static long bytes2long(byte[] bs) throws Exception {
int bytes = bs.length;
if (bytes > 1) {
if ((bytes % 2) != 0 || bytes > 8) {
throw new Exception("not support");
}
}
switch (bytes) {
case 0:
return 0;
case 1:
return (long) ((bs[0] & 0xff));
case 2:
return (long) ((bs[0] & 0xff) << 8 | (bs[1] & 0xff));
case 4:
return (long) ((bs[0] & 0xffL) << 24 | (bs[1] & 0xffL) << 16 | (bs[2] & 0xffL) << 8 | (bs[3] & 0xffL));
case 8:
return (long) ((bs[0] & 0xffL) << 56 | (bs[1] & 0xffL) << 48 | (bs[2] & 0xffL) << 40 | (bs[3] & 0xffL) << 32 |
(bs[4] & 0xffL) << 24 | (bs[5] & 0xffL) << 16 | (bs[6] & 0xffL) << 8 | (bs[7] & 0xffL));
default:
throw new Exception("not support");
}
//return 0;
}
public static long bytes2long(byte[] bs, int offset) {
return (long) ((bs[7 + offset] & 0xffL) << 56 | (bs[6 + offset] & 0xffL) << 48 | (bs[5 + offset] & 0xffL) << 40 | (bs[4 + offset] & 0xffL) << 32 |
(bs[3 + offset] & 0xffL) << 24 | (bs[2 + offset] & 0xffL) << 16 | (bs[1 + offset] & 0xffL) << 8 | (bs[0 + offset] & 0xffL));
}
public static byte[] hexStrToBytes(String hexStr, int len) {
if (TextUtils.isEmpty(hexStr) || hexStr.length() == 0) {
return null;
}
if (hexStr.length() % 2 == 1) {
hexStr = "0" + hexStr;
}
byte[] result = new byte[len];
char[] chars = hexStr.toCharArray();
int hexlen = hexStr.length();
if (hexlen > len)
hexlen = len;
for (int i = 0; i < hexlen - 1; i++) {
result[i] = (byte) (charToByte(chars[i]) << 4 | charToByte(chars[i + 1]));
}
return result;
}
private static byte charToByte(char c) {
String chars = "0123456789ABCDEF";
byte b = (byte) chars.indexOf(c);
return b;
}
/**
* Hex字符串转byte
*
* @param inHex 待转换的Hex字符串
* @return 转换后的byte
*/
public static byte hexToByte(String inHex) {
return (byte) Integer.parseInt(inHex, 16);
}
}
package iot.sixiang.license.util;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
/**
* Title: HmacShaUtils
* Description:
*
* @author YFW
* @version V1.0
* @date 2022-03-14
*/
public class HmacShaUtils {
private static final String HMAC_ALGORITHM = "hmacsha1";
private static final String secretKey = "90d2fca50ea8ed5472c5776c9fc53699";
/**
* 使用HMAC_ALGORITHM加密。
*
* @param content,明文。
* @param secret,密钥。
* @return 密文。
*/
public static String encrypt(String content, String secret) {
if (PubUtils.isNull(secret)) secret = secretKey;
try {
byte[] text = content.getBytes(StandardCharsets.UTF_8);
byte[] key = secret.getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKey = new SecretKeySpec(key, HMAC_ALGORITHM);
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
return byte2hex(mac.doFinal(text));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 二进制转十六进制字符串。
*
* @param b,二进制数组。
* @return 十六进制字符串。
*/
public static String byte2hex(byte[] b) {
StringBuffer sb = new StringBuffer();
for (int n = 0; b != null && n < b.length; n++) {
String stmp = Integer.toHexString(b[n] & 0XFF);
if (stmp.length() == 1) {
sb.append('0');
}
sb.append(stmp);
}
return sb.toString().toUpperCase();
}
}
package iot.sixiang.license.util.sm4;
import java.math.BigInteger;
public class ByteUtil {
/**
* 整形转换成网络传输的字节流(字节数组)型数据
*
* @param num 一个整型数据
* @return 4个字节的自己数组
*/
public static byte[] intToBytes(int num) {
byte[] bytes = new byte[4];
bytes[0] = (byte) (0xff & (num >> 0));
bytes[1] = (byte) (0xff & (num >> 8));
bytes[2] = (byte) (0xff & (num >> 16));
bytes[3] = (byte) (0xff & (num >> 24));
return bytes;
}
/**
* 四个字节的字节数据转换成一个整形数据
*
* @param bytes 4个字节的字节数组
* @return 一个整型数据
*/
public static int byteToInt(byte[] bytes) {
int num = 0;
int temp;
temp = (0x000000ff & (bytes[0])) << 0;
num = num | temp;
temp = (0x000000ff & (bytes[1])) << 8;
num = num | temp;
temp = (0x000000ff & (bytes[2])) << 16;
num = num | temp;
temp = (0x000000ff & (bytes[3])) << 24;
num = num | temp;
return num;
}
/**
* 长整形转换成网络传输的字节流(字节数组)型数据
*
* @param num 一个长整型数据
* @return 4个字节的自己数组
*/
public static byte[] longToBytes(long num) {
byte[] bytes = new byte[8];
for (int i = 0; i < 8; i++) {
bytes[i] = (byte) (0xff & (num >> (i * 8)));
}
return bytes;
}
/**
* 大数字转换字节流(字节数组)型数据
*
* @param n
* @return
*/
public static byte[] byteConvert32Bytes(BigInteger n) {
byte tmpd[] = (byte[]) null;
if (n == null) {
return null;
}
if (n.toByteArray().length == 33) {
tmpd = new byte[32];
System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32);
} else if (n.toByteArray().length == 32) {
tmpd = n.toByteArray();
} else {
tmpd = new byte[32];
for (int i = 0; i < 32 - n.toByteArray().length; i++) {
tmpd[i] = 0;
}
System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length);
}
return tmpd;
}
/**
* 换字节流(字节数组)型数据转大数字
*
* @param b
* @return
*/
public static BigInteger byteConvertInteger(byte[] b) {
if (b[0] < 0) {
byte[] temp = new byte[b.length + 1];
temp[0] = 0;
System.arraycopy(b, 0, temp, 1, b.length);
return new BigInteger(temp);
}
return new BigInteger(b);
}
/**
* 根据字节数组获得值(十六进制数字)
*
* @param bytes
* @return
*/
public static String getHexString(byte[] bytes) {
return getHexString(bytes, true);
}
/**
* 根据字节数组获得值(十六进制数字)
*
* @param bytes
* @param upperCase
* @return
*/
public static String getHexString(byte[] bytes, boolean upperCase) {
String ret = "";
for (int i = 0; i < bytes.length; i++) {
ret += Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1);
}
return upperCase ? ret.toUpperCase() : ret;
}
/**
* 打印十六进制字符串
*
* @param bytes
*/
public static void printHexString(byte[] bytes) {
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
System.out.print("0x" + hex.toUpperCase() + ",");
}
System.out.println("");
}
/**
* Convert hex string to byte[]
*
* @param hexString the hex string
* @return byte[]
*/
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
/**
* Convert char to byte
*
* @param c char
* @return byte
*/
public static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
/**
* 用于建立十六进制字符的输出的小写字符数组
*/
private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* 用于建立十六进制字符的输出的大写字符数组
*/
private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @return 十六进制char[]
*/
public static char[] encodeHex(byte[] data) {
return encodeHex(data, true);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制char[]
*/
public static char[] encodeHex(byte[] data, boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @param toDigits 用于控制输出的char[]
* @return 十六进制char[]
*/
protected static char[] encodeHex(byte[] data, char[] toDigits) {
int l = data.length;
char[] out = new char[l << 1];
// two characters form the hex value.
for (int i = 0, j = 0; i < l; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
return out;
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @return 十六进制String
*/
public static String encodeHexString(byte[] data) {
return encodeHexString(data, true);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制String
*/
public static String encodeHexString(byte[] data, boolean toLowerCase) {
return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @param toDigits 用于控制输出的char[]
* @return 十六进制String
*/
protected static String encodeHexString(byte[] data, char[] toDigits) {
return new String(encodeHex(data, toDigits));
}
/**
* 将十六进制字符数组转换为字节数组
*
* @param data 十六进制char[]
* @return byte[]
* @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
*/
public static byte[] decodeHex(char[] data) {
int len = data.length;
if ((len & 0x01) != 0) {
throw new RuntimeException("Odd number of characters.");
}
byte[] out = new byte[len >> 1];
// two characters form the hex value.
for (int i = 0, j = 0; j < len; i++) {
int f = toDigit(data[j], j) << 4;
j++;
f = f | toDigit(data[j], j);
j++;
out[i] = (byte) (f & 0xFF);
}
return out;
}
/**
* 将十六进制字符转换成一个整数
*
* @param ch 十六进制char
* @param index 十六进制字符在字符数组中的位置
* @return 一个整数
* @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常
*/
protected static int toDigit(char ch, int index) {
int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new RuntimeException("Illegal hexadecimal character " + ch
+ " at index " + index);
}
return digit;
}
/**
* 数字字符串转ASCII码字符串
*
* @param String 字符串
* @return ASCII字符串
*/
public static String StringToAsciiString(String content) {
String result = "";
int max = content.length();
for (int i = 0; i < max; i++) {
char c = content.charAt(i);
String b = Integer.toHexString(c);
result = result + b;
}
return result;
}
/**
* 十六进制转字符串
*
* @param hexString 十六进制字符串
* @param encodeType 编码类型4:Unicode,2:普通编码
* @return 字符串
*/
public static String hexStringToString(String hexString, int encodeType) {
String result = "";
int max = hexString.length() / encodeType;
for (int i = 0; i < max; i++) {
char c = (char) hexStringToAlgorism(hexString
.substring(i * encodeType, (i + 1) * encodeType));
result += c;
}
return result;
}
/**
* 十六进制字符串装十进制
*
* @param hex 十六进制字符串
* @return 十进制数值
*/
public static int hexStringToAlgorism(String hex) {
hex = hex.toUpperCase();
int max = hex.length();
int result = 0;
for (int i = max; i > 0; i--) {
char c = hex.charAt(i - 1);
int algorism = 0;
if (c >= '0' && c <= '9') {
algorism = c - '0';
} else {
algorism = c - 55;
}
result += Math.pow(16, max - i) * algorism;
}
return result;
}
/**
* 十六转二进制
*
* @param hex 十六进制字符串
* @return 二进制字符串
*/
public static String hexStringToBinary(String hex) {
hex = hex.toUpperCase();
String result = "";
int max = hex.length();
for (int i = 0; i < max; i++) {
char c = hex.charAt(i);
switch (c) {
case '0':
result += "0000";
break;
case '1':
result += "0001";
break;
case '2':
result += "0010";
break;
case '3':
result += "0011";
break;
case '4':
result += "0100";
break;
case '5':
result += "0101";
break;
case '6':
result += "0110";
break;
case '7':
result += "0111";
break;
case '8':
result += "1000";
break;
case '9':
result += "1001";
break;
case 'A':
result += "1010";
break;
case 'B':
result += "1011";
break;
case 'C':
result += "1100";
break;
case 'D':
result += "1101";
break;
case 'E':
result += "1110";
break;
case 'F':
result += "1111";
break;
}
}
return result;
}
/**
* ASCII码字符串转数字字符串
*
* @param String ASCII字符串
* @return 字符串
*/
public static String AsciiStringToString(String content) {
String result = "";
int length = content.length() / 2;
for (int i = 0; i < length; i++) {
String c = content.substring(i * 2, i * 2 + 2);
int a = hexStringToAlgorism(c);
char b = (char) a;
String d = String.valueOf(b);
result += d;
}
return result;
}
/**
* 将十进制转换为指定长度的十六进制字符串
*
* @param algorism int 十进制数字
* @param maxLength int 转换后的十六进制字符串长度
* @return String 转换后的十六进制字符串
*/
public static String algorismToHexString(int algorism, int maxLength) {
String result = "";
result = Integer.toHexString(algorism);
if (result.length() % 2 == 1) {
result = "0" + result;
}
return patchHexString(result.toUpperCase(), maxLength);
}
/**
* 字节数组转为普通字符串(ASCII对应的字符)
*
* @param bytearray byte[]
* @return String
*/
public static String byteToString(byte[] bytearray) {
String result = "";
char temp;
int length = bytearray.length;
for (int i = 0; i < length; i++) {
temp = (char) bytearray[i];
result += temp;
}
return result;
}
/**
* 二进制字符串转十进制
*
* @param binary 二进制字符串
* @return 十进制数值
*/
public static int binaryToAlgorism(String binary) {
int max = binary.length();
int result = 0;
for (int i = max; i > 0; i--) {
char c = binary.charAt(i - 1);
int algorism = c - '0';
result += Math.pow(2, max - i) * algorism;
}
return result;
}
/**
* 十进制转换为十六进制字符串
*
* @param algorism int 十进制的数字
* @return String 对应的十六进制字符串
*/
public static String algorismToHEXString(int algorism) {
String result = "";
result = Integer.toHexString(algorism);
if (result.length() % 2 == 1) {
result = "0" + result;
}
result = result.toUpperCase();
return result;
}
/**
* HEX字符串前补0,主要用于长度位数不足。
*
* @param str String 需要补充长度的十六进制字符串
* @param maxLength int 补充后十六进制字符串的长度
* @return 补充结果
*/
static public String patchHexString(String str, int maxLength) {
String temp = "";
for (int i = 0; i < maxLength - str.length(); i++) {
temp = "0" + temp;
}
str = (temp + str).substring(0, maxLength);
return str;
}
/**
* 将一个字符串转换为int
*
* @param s String 要转换的字符串
* @param defaultInt int 如果出现异常,默认返回的数字
* @param radix int 要转换的字符串是什么进制的,如16 8 10.
* @return int 转换后的数字
*/
public static int parseToInt(String s, int defaultInt, int radix) {
int i = 0;
try {
i = Integer.parseInt(s, radix);
} catch (NumberFormatException ex) {
i = defaultInt;
}
return i;
}
/**
* 将一个十进制形式的数字字符串转换为int
*
* @param s String 要转换的字符串
* @param defaultInt int 如果出现异常,默认返回的数字
* @return int 转换后的数字
*/
public static int parseToInt(String s, int defaultInt) {
int i = 0;
try {
i = Integer.parseInt(s);
} catch (NumberFormatException ex) {
i = defaultInt;
}
return i;
}
/**
* 十六进制串转化为byte数组
*
* @return the array of byte
*/
public static byte[] hexToByte(String hex)
throws IllegalArgumentException {
if (hex.length() % 2 != 0) {
throw new IllegalArgumentException();
}
char[] arr = hex.toCharArray();
byte[] b = new byte[hex.length() / 2];
for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
String swap = "" + arr[i++] + arr[i];
int byteint = Integer.parseInt(swap, 16) & 0xFF;
b[j] = new Integer(byteint).byteValue();
}
return b;
}
/**
* 字节数组转换为十六进制字符串
*
* @param b byte[] 需要转换的字节数组
* @return String 十六进制字符串
*/
public static String byteToHex(byte b[]) {
if (b == null) {
throw new IllegalArgumentException(
"Argument b ( byte array ) is null! ");
}
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = Integer.toHexString(b[n] & 0xff);
if (stmp.length() == 1) {
hs = hs + "0" + stmp;
} else {
hs = hs + stmp;
}
}
return hs.toUpperCase();
}
public static byte[] subByte(byte[] input, int startIndex, int length) {
byte[] bt = new byte[length];
for (int i = 0; i < length; i++) {
bt[i] = input[i + startIndex];
}
return bt;
}
}
package iot.sixiang.license.util.sm4;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
public class SM4 {
public static final int SM4_ENCRYPT = 1;
public static final int SM4_DECRYPT = 0;
private long GET_ULONG_BE(byte[] b, int i) {
long n = (long) (b[i] & 0xff) << 24 | (long) ((b[i + 1] & 0xff) << 16) | (long) ((b[i + 2] & 0xff) << 8) | (long) (b[i + 3] & 0xff) & 0xffffffffL;
return n;
}
private void PUT_ULONG_BE(long n, byte[] b, int i) {
b[i] = (byte) (int) (0xFF & n >> 24);
b[i + 1] = (byte) (int) (0xFF & n >> 16);
b[i + 2] = (byte) (int) (0xFF & n >> 8);
b[i + 3] = (byte) (int) (0xFF & n);
}
private long SHL(long x, int n) {
return (x & 0xFFFFFFFF) << n;
}
private long ROTL(long x, int n) {
return SHL(x, n) | x >> (32 - n);
}
private void SWAP(long[] sk, int i) {
long t = sk[i];
sk[i] = sk[(31 - i)];
sk[(31 - i)] = t;
}
public static final byte[] SboxTable = {(byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe,
(byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6,
0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67,
(byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3,
(byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06,
(byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91,
(byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43,
(byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4,
(byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8,
(byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa,
0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7,
(byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83,
0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8,
0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda,
(byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56,
(byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1,
(byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87,
(byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27,
0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4,
(byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a,
(byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3,
(byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15,
(byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4,
(byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32,
0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d,
(byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca,
0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f,
(byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd,
(byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b,
0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb,
(byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41,
0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31,
(byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d,
0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4,
(byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c,
(byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09,
(byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0,
0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79,
(byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48};
public static final int[] FK = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};
public static final int[] CK = {0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279};
private byte sm4Sbox(byte inch) {
int i = inch & 0xFF;
byte retVal = SboxTable[i];
return retVal;
}
private long sm4Lt(long ka) {
long bb = 0L;
long c = 0L;
byte[] a = new byte[4];
byte[] b = new byte[4];
PUT_ULONG_BE(ka, a, 0);
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
bb = GET_ULONG_BE(b, 0);
c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24);
return c;
}
private long sm4F(long x0, long x1, long x2, long x3, long rk) {
return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
}
private long sm4CalciRK(long ka) {
long bb = 0L;
long rk = 0L;
byte[] a = new byte[4];
byte[] b = new byte[4];
PUT_ULONG_BE(ka, a, 0);
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
bb = GET_ULONG_BE(b, 0);
rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23);
return rk;
}
private void sm4_setkey(long[] SK, byte[] key) {
long[] MK = new long[4];
long[] k = new long[36];
int i = 0;
MK[0] = GET_ULONG_BE(key, 0);
MK[1] = GET_ULONG_BE(key, 4);
MK[2] = GET_ULONG_BE(key, 8);
MK[3] = GET_ULONG_BE(key, 12);
k[0] = MK[0] ^ (long) FK[0];
k[1] = MK[1] ^ (long) FK[1];
k[2] = MK[2] ^ (long) FK[2];
k[3] = MK[3] ^ (long) FK[3];
for (; i < 32; i++) {
k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ (long) CK[i]));
SK[i] = k[(i + 4)];
}
}
public void sm4_one_round(long[] sk, byte[] input, byte[] output) {
int i = 0;
long[] ulbuf = new long[36];
ulbuf[0] = GET_ULONG_BE(input, 0);
ulbuf[1] = GET_ULONG_BE(input, 4);
ulbuf[2] = GET_ULONG_BE(input, 8);
ulbuf[3] = GET_ULONG_BE(input, 12);
while (i < 32) {
ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3)], sk[i]);
i++;
}
PUT_ULONG_BE(ulbuf[35], output, 0);
PUT_ULONG_BE(ulbuf[34], output, 4);
PUT_ULONG_BE(ulbuf[33], output, 8);
PUT_ULONG_BE(ulbuf[32], output, 12);
}
private byte[] padding(byte[] input, int mode) {
if (input == null) {
return null;
}
byte[] ret = (byte[]) null;
if (mode == SM4_ENCRYPT) {
int p = 16 - input.length % 16;
ret = new byte[input.length + p];
System.arraycopy(input, 0, ret, 0, input.length);
for (int i = 0; i < p; i++) {
ret[input.length + i] = (byte) p;
}
} else {
int p = input[input.length - 1];
ret = new byte[input.length - p];
System.arraycopy(input, 0, ret, 0, input.length - p);
}
return ret;
}
public void sm4_setkey_enc(SM4Context ctx, byte[] key) throws Exception {
if (ctx == null) {
throw new Exception("ctx is null!");
}
if (key == null || key.length != 16) {
throw new Exception("key error!");
}
ctx.mode = SM4_ENCRYPT;
sm4_setkey(ctx.sk, key);
}
public void sm4_setkey_dec(SM4Context ctx, byte[] key) throws Exception {
if (ctx == null) {
throw new Exception("ctx is null!");
}
if (key == null || key.length != 16) {
throw new Exception("key error!");
}
int i = 0;
ctx.mode = SM4_DECRYPT;
sm4_setkey(ctx.sk, key);
for (i = 0; i < 16; i++) {
SWAP(ctx.sk, i);
}
}
public byte[] sm4_crypt_ecb(SM4Context ctx, byte[] input) throws Exception {
if (input == null) {
throw new Exception("input is null!");
}
if ((ctx.isPadding) && (ctx.mode == SM4_ENCRYPT)) {
input = padding(input, SM4_ENCRYPT);
}
int length = input.length;
ByteArrayInputStream bins = new ByteArrayInputStream(input);
ByteArrayOutputStream bous = new ByteArrayOutputStream();
for (; length > 0; length -= 16) {
byte[] in = new byte[16];
byte[] out = new byte[16];
bins.read(in);
sm4_one_round(ctx.sk, in, out);
bous.write(out);
}
byte[] output = bous.toByteArray();
if (ctx.isPadding && ctx.mode == SM4_DECRYPT) {
output = padding(output, SM4_DECRYPT);
}
bins.close();
bous.close();
return output;
}
public byte[] sm4_crypt_cbc(SM4Context ctx, byte[] iv, byte[] input) throws Exception {
if (iv == null || iv.length != 16) {
throw new Exception("iv error!");
}
if (input == null) {
throw new Exception("input is null!");
}
if (ctx.isPadding && ctx.mode == SM4_ENCRYPT) {
input = padding(input, SM4_ENCRYPT);
}
int i = 0;
int length = input.length;
ByteArrayInputStream bins = new ByteArrayInputStream(input);
ByteArrayOutputStream bous = new ByteArrayOutputStream();
if (ctx.mode == SM4_ENCRYPT) {
for (; length > 0; length -= 16) {
byte[] in = new byte[16];
byte[] out = new byte[16];
byte[] out1 = new byte[16];
bins.read(in);
for (i = 0; i < 16; i++) {
out[i] = ((byte) (in[i] ^ iv[i]));
}
sm4_one_round(ctx.sk, out, out1);
System.arraycopy(out1, 0, iv, 0, 16);
bous.write(out1);
}
} else {
byte[] temp = new byte[16];
for (; length > 0; length -= 16) {
byte[] in = new byte[16];
byte[] out = new byte[16];
byte[] out1 = new byte[16];
bins.read(in);
System.arraycopy(in, 0, temp, 0, 16);
sm4_one_round(ctx.sk, in, out);
for (i = 0; i < 16; i++) {
out1[i] = ((byte) (out[i] ^ iv[i]));
}
System.arraycopy(temp, 0, iv, 0, 16);
bous.write(out1);
}
}
byte[] output = bous.toByteArray();
if (ctx.isPadding && ctx.mode == SM4_DECRYPT) {
output = padding(output, SM4_DECRYPT);
}
bins.close();
bous.close();
return output;
}
}
package iot.sixiang.license.util.sm4;
public class SM4Context {
public int mode;
public long[] sk;
public boolean isPadding;
public SM4Context() {
this.mode = 1;
this.isPadding = true;
this.sk = new long[32];
}
}
package iot.sixiang.license.util.sm4;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SM4Utils {
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public boolean isHexString() {
return hexString;
}
public void setHexString(boolean hexString) {
this.hexString = hexString;
}
private String secretKey = "";
public String getIv() {
return iv;
}
public void setIv(String iv) {
this.iv = iv;
}
private String iv = "";
private boolean hexString = false;
public SM4Utils() {
}
public String encryptData_ECB(String plainText) {
try {
SM4Context ctx = new SM4Context();
ctx.isPadding = true;
ctx.mode = SM4.SM4_ENCRYPT;
byte[] keyBytes;
if (hexString) {
keyBytes = ByteUtil.hexStringToBytes(secretKey);
} else {
keyBytes = secretKey.getBytes();
}
SM4 sm4 = new SM4();
sm4.sm4_setkey_enc(ctx, keyBytes);
byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText.getBytes("UTF-8"));
String cipherText = Base64.getEncoder().encodeToString(encrypted);
if (cipherText != null && cipherText.trim().length() > 0) {
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(cipherText);
cipherText = m.replaceAll("");
}
return cipherText;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public String decryptData_ECB(String cipherText) {
try {
SM4Context ctx = new SM4Context();
ctx.isPadding = true;
ctx.mode = SM4.SM4_DECRYPT;
byte[] keyBytes;
if (hexString) {
keyBytes = ByteUtil.hexStringToBytes(secretKey);
} else {
keyBytes = secretKey.getBytes();
}
SM4 sm4 = new SM4();
sm4.sm4_setkey_dec(ctx, keyBytes);
byte[] decrypted = sm4.sm4_crypt_ecb(ctx, Base64.getDecoder().decode(cipherText));
return new String(decrypted, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public String encryptData_CBC(String plainText) {
try {
SM4Context ctx = new SM4Context();
ctx.isPadding = true;
ctx.mode = SM4.SM4_ENCRYPT;
byte[] keyBytes;
byte[] ivBytes;
if (hexString) {
keyBytes = ByteUtil.hexStringToBytes(secretKey);
ivBytes = ByteUtil.hexStringToBytes(iv);
} else {
keyBytes = secretKey.getBytes();
ivBytes = iv.getBytes();
}
SM4 sm4 = new SM4();
sm4.sm4_setkey_enc(ctx, keyBytes);
byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainText.getBytes("UTF-8"));
String cipherText = Base64.getEncoder().encodeToString(encrypted);
if (cipherText != null && cipherText.trim().length() > 0) {
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(cipherText);
cipherText = m.replaceAll("");
}
return cipherText;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public String decryptData_CBC(String cipherText) {
try {
SM4Context ctx = new SM4Context();
ctx.isPadding = true;
ctx.mode = SM4.SM4_DECRYPT;
byte[] keyBytes;
byte[] ivBytes;
if (hexString) {
keyBytes = ByteUtil.hexStringToBytes(secretKey);
ivBytes = ByteUtil.hexStringToBytes(iv);
} else {
keyBytes = secretKey.getBytes();
ivBytes = iv.getBytes();
}
SM4 sm4 = new SM4();
sm4.sm4_setkey_dec(ctx, keyBytes);
byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Base64.getDecoder().decode(cipherText));
return new String(decrypted, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment