From 014ac7931eef46b5b0237d744c6a373faa94f342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B4=BE=E5=90=8C=E5=AD=A6?= Date: Tue, 14 Oct 2025 18:54:32 +0800 Subject: [PATCH] =?UTF-8?q?ADD:=20=E7=A8=8B=E5=BA=8F=E6=BF=80=E6=B4=BB?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=EF=BC=9A1=E3=80=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=94=B3=E8=AF=B7=E7=A0=81=EF=BC=9B2?= =?UTF-8?q?=E3=80=81=E9=AA=8C=E8=AF=81=E8=AE=BE=E5=A4=87=E6=BF=80=E6=B4=BB?= =?UTF-8?q?=E7=A0=81=EF=BC=9B3=E3=80=81=E8=AF=BB=E5=8F=96=E8=AE=B8?= =?UTF-8?q?=E5=8F=AF=E4=BF=A1=E6=81=AF=EF=BC=9B4=E3=80=81=E6=BF=80?= =?UTF-8?q?=E6=B4=BB=E7=A0=81=E7=94=9F=E6=88=90=E5=B7=A5=E5=85=B7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gather/activate/config/RSAProperties.java | 17 +++ .../controller/ActivateController.java | 74 ++++++++++ .../pojo/vo/ActivationCodePlaintext.java | 35 +++++ .../activate/pojo/vo/ActivationModule.java | 20 +++ .../pojo/vo/ApplicationCodePlaintext.java | 35 +++++ .../activate/pojo/vo/ApplicationModule.java | 17 +++ .../activate/service/ActivateService.java | 30 ++++ .../service/impl/ActivateServiceImpl.java | 134 ++++++++++++++++++ entrance/src/main/resources/application.yml | 12 +- pom.xml | 1 + tools/activate-tool/pom.xml | 50 +++++++ .../tool/active/ActivateToolApplication.java | 15 ++ .../tool/active/config/RSAProperties.java | 17 +++ .../active/controller/ActivateController.java | 42 ++++++ .../tool/active/service/ActivateService.java | 15 ++ .../service/impl/ActivateServiceImpl.java | 65 +++++++++ .../active/vo/ActivationCodePlaintext.java | 28 ++++ .../tool/active/vo/ActivationModule.java | 15 ++ .../active/vo/ApplicationCodePlaintext.java | 28 ++++ .../tool/active/vo/ApplicationModule.java | 15 ++ .../src/main/resources/application.yml | 8 ++ tools/pom.xml | 1 + 22 files changed, 670 insertions(+), 4 deletions(-) create mode 100644 detection/src/main/java/com/njcn/gather/activate/config/RSAProperties.java create mode 100644 detection/src/main/java/com/njcn/gather/activate/controller/ActivateController.java create mode 100644 detection/src/main/java/com/njcn/gather/activate/pojo/vo/ActivationCodePlaintext.java create mode 100644 detection/src/main/java/com/njcn/gather/activate/pojo/vo/ActivationModule.java create mode 100644 detection/src/main/java/com/njcn/gather/activate/pojo/vo/ApplicationCodePlaintext.java create mode 100644 detection/src/main/java/com/njcn/gather/activate/pojo/vo/ApplicationModule.java create mode 100644 detection/src/main/java/com/njcn/gather/activate/service/ActivateService.java create mode 100644 detection/src/main/java/com/njcn/gather/activate/service/impl/ActivateServiceImpl.java create mode 100644 tools/activate-tool/pom.xml create mode 100644 tools/activate-tool/src/main/java/com/njcn/gather/tool/active/ActivateToolApplication.java create mode 100644 tools/activate-tool/src/main/java/com/njcn/gather/tool/active/config/RSAProperties.java create mode 100644 tools/activate-tool/src/main/java/com/njcn/gather/tool/active/controller/ActivateController.java create mode 100644 tools/activate-tool/src/main/java/com/njcn/gather/tool/active/service/ActivateService.java create mode 100644 tools/activate-tool/src/main/java/com/njcn/gather/tool/active/service/impl/ActivateServiceImpl.java create mode 100644 tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ActivationCodePlaintext.java create mode 100644 tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ActivationModule.java create mode 100644 tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ApplicationCodePlaintext.java create mode 100644 tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ApplicationModule.java create mode 100644 tools/activate-tool/src/main/resources/application.yml diff --git a/detection/src/main/java/com/njcn/gather/activate/config/RSAProperties.java b/detection/src/main/java/com/njcn/gather/activate/config/RSAProperties.java new file mode 100644 index 00000000..8687467a --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/activate/config/RSAProperties.java @@ -0,0 +1,17 @@ +package com.njcn.gather.activate.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Data +@ConfigurationProperties(prefix = "rsa") +public class RSAProperties { + /** + * RSA公钥 + */ + private String publicKey; + /** + * RSA私钥 + */ + private String privateKey; +} diff --git a/detection/src/main/java/com/njcn/gather/activate/controller/ActivateController.java b/detection/src/main/java/com/njcn/gather/activate/controller/ActivateController.java new file mode 100644 index 00000000..612483fa --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/activate/controller/ActivateController.java @@ -0,0 +1,74 @@ +package com.njcn.gather.activate.controller; + +import cn.hutool.json.JSONUtil; +import com.njcn.common.pojo.annotation.OperateInfo; +import com.njcn.common.pojo.enums.common.LogEnum; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.LogUtil; +import com.njcn.gather.activate.pojo.vo.ActivationCodePlaintext; +import com.njcn.gather.activate.pojo.vo.ApplicationCodePlaintext; +import com.njcn.gather.activate.service.ActivateService; +import com.njcn.web.controller.BaseController; +import com.njcn.web.utils.HttpResultUtil; +import io.swagger.annotations.*; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +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.RestController; + +@Slf4j +@Api(tags = "设备激活管理") +@RestController +@RequestMapping("/activate") +@RequiredArgsConstructor +public class ActivateController extends BaseController { + + private final ActivateService activateService; + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @ApiOperation("生成设备申请码") + @ApiImplicitParam(name = "data", value = "生成设备申请码参数", required = true) + @PostMapping("/generateApplicationCode") + public HttpResult generateApplicationCode(@RequestBody ApplicationCodePlaintext data) { + String methodDescribe = getMethodDescribe("generateApplicationCode"); + LogUtil.njcnDebug(log, "{},生成设备申请码:{}", methodDescribe, JSONUtil.toJsonStr(data)); + String applicationCode = activateService.generateApplicationCode(data); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, applicationCode, methodDescribe); + } + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @ApiOperation("验证设备激活码") + @ApiImplicitParam(name = "params", value = "验证设备激活码参数", required = true) + @PostMapping("/verifyActivationCode") + public HttpResult verifyActivationCode(@RequestBody VerifyActivationCodeParams params) { + String methodDescribe = getMethodDescribe("verifyActivationCode"); + LogUtil.njcnDebug(log, "{},验证设备激活码\":{}", methodDescribe, JSONUtil.toJsonStr(params)); + ActivationCodePlaintext activationCodePlaintext = activateService.verifyActivationCode(params.getActivationCode()); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, activationCodePlaintext, methodDescribe); + } + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @ApiOperation("获取许可信息") + @PostMapping("/getLicense") + public HttpResult getLicense() { + String methodDescribe = getMethodDescribe("checkLicense"); + LogUtil.njcnDebug(log, "{},获取许可信息", methodDescribe); + ActivationCodePlaintext activationCodePlaintext = activateService.readLicenseFile(); + if (activationCodePlaintext == null) { + activationCodePlaintext = new ActivationCodePlaintext(); + activationCodePlaintext.init(); + } + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, activationCodePlaintext, methodDescribe); + } + + @ApiModel("验证设备激活码参数") + @Data + public static class VerifyActivationCodeParams { + @ApiModelProperty(value = "激活码") + private String activationCode; + } +} diff --git a/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ActivationCodePlaintext.java b/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ActivationCodePlaintext.java new file mode 100644 index 00000000..388be796 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ActivationCodePlaintext.java @@ -0,0 +1,35 @@ +package com.njcn.gather.activate.pojo.vo; + +import lombok.Data; + +@Data +public class ActivationCodePlaintext { + /** + * mac地址 + */ + private String macAddress; + + /** + * 模拟式模块 + */ + private ActivationModule simulate; + + /** + * 数字式模块 + */ + private ActivationModule digital; + + /** + * 比对式模块 + */ + private ActivationModule contrast; + + + public void init() { + simulate = new ActivationModule(); + digital = new ActivationModule(); + contrast = new ActivationModule(); + } + + +} diff --git a/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ActivationModule.java b/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ActivationModule.java new file mode 100644 index 00000000..4b82d2aa --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ActivationModule.java @@ -0,0 +1,20 @@ +package com.njcn.gather.activate.pojo.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class ActivationModule extends ApplicationModule { + + /** + * 是否永久授权 + */ + private int permanently; + + public boolean isPermanently() { + return permanently == 1; + } + + +} \ No newline at end of file diff --git a/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ApplicationCodePlaintext.java b/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ApplicationCodePlaintext.java new file mode 100644 index 00000000..aa06d18b --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ApplicationCodePlaintext.java @@ -0,0 +1,35 @@ +package com.njcn.gather.activate.pojo.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel("申请码明文") +@Data +public class ApplicationCodePlaintext { + /** + * mac地址 + */ + @ApiModelProperty(value = "mac地址", hidden = true) + private String macAddress; + + /** + * 模拟式模块 + */ + @ApiModelProperty("模拟式模块") + private ApplicationModule simulate; + + /** + * 数字式模块 + */ + @ApiModelProperty("数字式模块") + private ApplicationModule digital; + + /** + * 比对式模块 + */ + @ApiModelProperty("比对式模块") + private ApplicationModule contrast; + + +} diff --git a/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ApplicationModule.java b/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ApplicationModule.java new file mode 100644 index 00000000..eea0e1b2 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/activate/pojo/vo/ApplicationModule.java @@ -0,0 +1,17 @@ +package com.njcn.gather.activate.pojo.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class ApplicationModule { + /** + * 是否申请 1是 0否 + */ + @ApiModelProperty(value = "是否申请 1是 0否") + private int apply; + + public boolean isApply() { + return apply == 1; + } +} \ No newline at end of file diff --git a/detection/src/main/java/com/njcn/gather/activate/service/ActivateService.java b/detection/src/main/java/com/njcn/gather/activate/service/ActivateService.java new file mode 100644 index 00000000..5665e8a9 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/activate/service/ActivateService.java @@ -0,0 +1,30 @@ +package com.njcn.gather.activate.service; + +import com.njcn.gather.activate.pojo.vo.ActivationCodePlaintext; +import com.njcn.gather.activate.pojo.vo.ApplicationCodePlaintext; + +public interface ActivateService { + + /** + * 生成设备申请码 + * + * @param data + * @return + */ + String generateApplicationCode(ApplicationCodePlaintext data); + + /** + * 验证激活码 + * + * @param activationCode + * @return + */ + ActivationCodePlaintext verifyActivationCode(String activationCode); + + /** + * 读取授权文件 + * + * @return + */ + ActivationCodePlaintext readLicenseFile(); +} diff --git a/detection/src/main/java/com/njcn/gather/activate/service/impl/ActivateServiceImpl.java b/detection/src/main/java/com/njcn/gather/activate/service/impl/ActivateServiceImpl.java new file mode 100644 index 00000000..80191b0d --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/activate/service/impl/ActivateServiceImpl.java @@ -0,0 +1,134 @@ +package com.njcn.gather.activate.service.impl; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.net.NetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.utils.RSAUtil; +import com.njcn.gather.activate.config.RSAProperties; +import com.njcn.gather.activate.pojo.vo.ActivationCodePlaintext; +import com.njcn.gather.activate.pojo.vo.ActivationModule; +import com.njcn.gather.activate.pojo.vo.ApplicationCodePlaintext; +import com.njcn.gather.activate.service.ActivateService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.stereotype.Service; + +import java.io.File; + +@RequiredArgsConstructor +@Slf4j +@Service +@EnableConfigurationProperties(RSAProperties.class) +public class ActivateServiceImpl implements ActivateService { + private final RSAProperties rsaProperties; + static final String LICENSE_FILE_NAME = "license.key"; + static final String LICENSE_FILE_PATH = ActivateServiceImpl.class.getProtectionDomain().getCodeSource().getLocation().getPath() + File.separator + LICENSE_FILE_NAME; + + @Override + public String generateApplicationCode(ApplicationCodePlaintext data) { + // 获取当前设备MAC地址 + String macAddress = NetUtil.getLocalMacAddress(); + log.debug("当前设备MAC地址:{}", macAddress); + data.setMacAddress(macAddress); + String plaintext = JSONUtil.toJsonStr(data); + // RSA 加密 + try { + return RSAUtil.encrypt(plaintext, RSAUtil.stringToPublicKey(rsaProperties.getPublicKey())); + } catch (Exception e) { + log.error("申请码加密失败", e); + throw new BusinessException(CommonResponseEnum.FAIL, "申请码生成失败"); + } + } + + @Override + public ActivationCodePlaintext verifyActivationCode(String activationCode) { + String plaintext; + try { + plaintext = RSAUtil.decrypt(activationCode, RSAUtil.stringToPrivateKey(rsaProperties.getPrivateKey())); + } catch (Exception e) { + log.error("授权码解密失败", e); + throw new BusinessException(CommonResponseEnum.FAIL, "无效的激活码"); + } + log.info("新授权码解密:{}", JSONUtil.toJsonStr(plaintext)); + ActivationCodePlaintext activationCodePlaintext = JSONUtil.toBean(plaintext, ActivationCodePlaintext.class); + String macAddress = NetUtil.getLocalMacAddress(); + if (!StrUtil.equals(activationCodePlaintext.getMacAddress(), macAddress)) { + log.error("mac地址不匹配"); + throw new BusinessException(CommonResponseEnum.FAIL, "无效的激活码"); + } + return addOrUpdateLicenseFile(activationCodePlaintext, activationCode); + } + + @Override + public ActivationCodePlaintext readLicenseFile() { + if (FileUtil.exist(LICENSE_FILE_PATH)) { + String content = FileUtil.readUtf8String(LICENSE_FILE_PATH); + String plaintext; + try { + plaintext = RSAUtil.decrypt(content, RSAUtil.stringToPrivateKey(rsaProperties.getPrivateKey())); + } catch (Exception e) { + log.error("授权文件内容解密失败", e); + throw new BusinessException(CommonResponseEnum.FAIL, "许可信息读取失败"); + } + return JSONUtil.toBean(plaintext, ActivationCodePlaintext.class); + } + return null; + } + + private ActivationCodePlaintext addOrUpdateLicenseFile(ActivationCodePlaintext newActivationCodePlaintext, String activationCode) { + log.info("新授权码明文:{}", JSONUtil.toJsonStr(newActivationCodePlaintext)); + ActivationModule newContrast = newActivationCodePlaintext.getContrast(); + ActivationModule newDigital = newActivationCodePlaintext.getDigital(); + ActivationModule newSimulate = newActivationCodePlaintext.getSimulate(); + boolean verifyStatus = false; + if (newContrast.isApply() && newContrast.isPermanently()) { + verifyStatus = true; + } + if (newDigital.isApply() && newDigital.isPermanently()) { + verifyStatus = true; + } + if (newSimulate.isApply() && newSimulate.isPermanently()) { + verifyStatus = true; + } + if (!verifyStatus) { + log.error("授权码格式错误"); + throw new BusinessException(CommonResponseEnum.FAIL, "无效的激活码"); + } + log.info("授权文件路径:{}", LICENSE_FILE_PATH); + ActivationCodePlaintext oldActivationCodePlaintext = this.readLicenseFile(); + if (oldActivationCodePlaintext == null) { + // 如果文件不存在,创建新文件 + FileUtil.touch(LICENSE_FILE_PATH); + // 写入授权文件 + FileUtil.writeUtf8String(activationCode, LICENSE_FILE_PATH); + return newActivationCodePlaintext; + } else { + log.info("旧授权码明文:{}", JSONUtil.toJsonStr(oldActivationCodePlaintext)); + if (newContrast.isApply()) { + oldActivationCodePlaintext.setContrast(newContrast); + } + if (newDigital.isApply()) { + oldActivationCodePlaintext.setDigital(newDigital); + } + if (newSimulate.isApply()) { + oldActivationCodePlaintext.setSimulate(newSimulate); + } + log.info("最新授权码明文:{}", JSONUtil.toJsonStr(oldActivationCodePlaintext)); + String updateContent; + // 重新加密 + try { + updateContent = RSAUtil.encrypt(JSONUtil.toJsonStr(oldActivationCodePlaintext), RSAUtil.stringToPublicKey(rsaProperties.getPublicKey())); + } catch (Exception e) { + log.error("授权文件内容加密失败", e); + throw new BusinessException(CommonResponseEnum.FAIL, "激活失败,请联系管理员"); + } + FileUtil.writeUtf8String(updateContent, LICENSE_FILE_PATH); + return oldActivationCodePlaintext; + } + } + +} diff --git a/entrance/src/main/resources/application.yml b/entrance/src/main/resources/application.yml index ccb3f829..591765ad 100644 --- a/entrance/src/main/resources/application.yml +++ b/entrance/src/main/resources/application.yml @@ -6,12 +6,12 @@ spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver -# url: jdbc:mysql://192.168.1.24:13306/pqs9100?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true -# username: root -# password: njcnpqs - url: jdbc:mysql://localhost:13306/pqs9100member?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true + url: jdbc:mysql://192.168.1.24:13306/pqs9100_client1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true username: root password: njcnpqs + # url: jdbc:mysql://localhost:3306/pqs91001?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=CTT + # username: root + # password: root #初始化建立物理连接的个数、最小、最大连接数 initial-size: 5 min-idle: 5 @@ -118,3 +118,7 @@ power-quality: harmonic-times: 50 # 谐波次数 ib-add: false # 电流基波叠加标志 uharm-add: false # 电压谐波叠加标志 +# rsa公私钥 +rsa: + private-key: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcUyYhVqczGxblL+o/xZzF/8nf+LjrfUE/dS1aRHM7uMDD0cgCArhjtfneFePrMxt+Z7W8yNBzSarub8qsfhaVNikV7Es7oaeTygfjQXTi2n4AFkir3fM07J08RpWhl5M8f8uWTCuvFUYAw00gq55typqmnbkmJa2VIUy/iQf+cMCP7abz4/jNhUzUR3qA7TV4oMRgTdIEDUp63YF8dOC+JH8XxYrCVeHXV6fLCwmesdMzl0lB2VTEKMfLbXhOmF5g7P9y/16VCcN8UBuZlbyYfn+GAxJOSbeHi5HshOKfoSuD7Jz+3WQZpNavOWjIFExKIU38/CvnJCOP7XBCqpSTAgMBAAECggEAYeWokWRE3TpvwiOZnUpR/aVMdVi75a3ROL5XIpqPV61B+t/bU3cEpl0GF9C5pUeiRi0IoStZb3mI9D1KPW/REKyUWkhabQO1gFYbTnRlkNOn6MILzKX4cwJjDaZeeo4EBPU7N+qHyOOXrU6hdH5FfxhMdV983ajm5eeuupxER1C2kAcIklTeVpTX6EKOgZb5LBp5ssOVm2P42pOauvcRozRcvZmqnErXmukv0H4l3EVNt4rHpTn9riHUC63e8JfiYzVaF6zuNUxv6nHEft0/SRMw11XSTnNfDzcKqgjz6ksFBS/6eQQYKESk+ONC53HUuYHFAknkwsPupDCT2W8FIQKBgQDLHT/xCU3nxGr4vFKBDNaO2D5oK20ECbBO4oDvLWWmQG7f+6TsMy8PgVdMnoL4RfqGlwFAKEpS6KVFHnBVqnNEhcdy9uCI7x7Xx8UnyUtxj1EDTm76uta9Ki9OrlqB6tImDM9+Ya3vGktW37ht4WOx2OsJRhG1dbf6RLwFlH7DWwKBgQDFBxvi5I1BR6hg6Tj7xd2SqOT2Y+BED3xuSYENhWbmMhLJDResaB7mjztbxlYaY2mOE0holWm2uDmVFFhMh4jYXik4hYH8nmDzq9mDpZCZ9pyjYqnAP8THoAa8EbgrUWB8A6BPH4iL3KbMnBfBKY0pIr2xrvnjQjNBAgta7KDRKQKBgCe6oe4wxrdF2TKsC2tIqpMoQxS3Icy/ZGgZr+SYuaBKTCWtoDW/UT40K3JGMxIDBhzbXphBCUCsVt9tM8Xd4EwP6tJW7dZ7B0pnve2pVwNwaAVAiz6p2yUHIle+jN+Koe5lZRSwYIg7WW81tWpwwsJfzqFyvjYDP6hJV4mz4ROvAoGAaRcdnKvjXApomShMqJ4lTPChD3q+SA8qg3jZSOj6tZXHx00gb2kp8jg7pPvpOTIFPy6x1Ha9aCRjMk0ju84fA6lVuzwa1S907wOehUVuF3Eeo1cgy9Y3k3KbpPyeixxgpkUY4JslLdSHc2NemD0dee951qhJyRmqVOZOQDUuoeECgYEAqBw2cAFk3vM97WY06TSldGA8ajVHx3BYRjj+zl62NTQthy8fw3tqxb3c5e8toOmZWKjZvDhg2TRLhsDDQWEYg3LZG87REqVIjgEPcpjNLidjygGX8n3JF2o0O5I/EMvl0s/+LVQONfduOBvhwDqr8QNisbLsyneiAq7umewMolo=" + public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnFMmIVanMxsW5S/qP8Wcxf/J3/i4631BP3UtWkRzO7jAw9HIAgK4Y7X53hXj6zMbfme1vMjQc0mq7m/KrH4WlTYpFexLO6Gnk8oH40F04tp+ABZIq93zNOydPEaVoZeTPH/LlkwrrxVGAMNNIKuebcqapp25JiWtlSFMv4kH/nDAj+2m8+P4zYVM1Ed6gO01eKDEYE3SBA1Ket2BfHTgviR/F8WKwlXh11enywsJnrHTM5dJQdlUxCjHy214TpheYOz/cv9elQnDfFAbmZW8mH5/hgMSTkm3h4uR7ITin6Erg+yc/t1kGaTWrzloyBRMSiFN/Pwr5yQjj+1wQqqUkwIDAQAB" \ No newline at end of file diff --git a/pom.xml b/pom.xml index e52be1a5..68d6a140 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ storage tools + tools/activate-tool pom 融合各工具的项目 diff --git a/tools/activate-tool/pom.xml b/tools/activate-tool/pom.xml new file mode 100644 index 00000000..40ef358d --- /dev/null +++ b/tools/activate-tool/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + com.njcn.gather + CN_Gather + 1.0.0 + + + activate-tool + + + 8 + 8 + UTF-8 + + + + + com.njcn + njcn-common + 0.0.1 + + + + com.njcn + spingboot2.3.12 + 2.3.12 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + \ No newline at end of file diff --git a/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/ActivateToolApplication.java b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/ActivateToolApplication.java new file mode 100644 index 00000000..4a308e79 --- /dev/null +++ b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/ActivateToolApplication.java @@ -0,0 +1,15 @@ +package com.njcn.gather.tool.active; + +import com.njcn.gather.tool.active.config.RSAProperties; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@EnableConfigurationProperties(RSAProperties.class) +@SpringBootApplication +public class ActivateToolApplication { + + public static void main(String[] args) { + SpringApplication.run(ActivateToolApplication.class, args); + } +} diff --git a/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/config/RSAProperties.java b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/config/RSAProperties.java new file mode 100644 index 00000000..c24e4700 --- /dev/null +++ b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/config/RSAProperties.java @@ -0,0 +1,17 @@ +package com.njcn.gather.tool.active.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Data +@ConfigurationProperties(prefix = "rsa") +public class RSAProperties { + /** + * RSA公钥 + */ + private String publicKey; + /** + * RSA私钥 + */ + private String privateKey; +} diff --git a/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/controller/ActivateController.java b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/controller/ActivateController.java new file mode 100644 index 00000000..68ff7267 --- /dev/null +++ b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/controller/ActivateController.java @@ -0,0 +1,42 @@ +package com.njcn.gather.tool.active.controller; + +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.gather.tool.active.service.ActivateService; +import com.njcn.web.controller.BaseController; +import com.njcn.web.utils.HttpResultUtil; +import io.swagger.annotations.*; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +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.RestController; + +@Slf4j +@Api(tags = "设备激活管理") +@RestController +@RequestMapping("/activate") +@RequiredArgsConstructor +public class ActivateController extends BaseController { + + private final ActivateService activateService; + + @ApiOperation("生成设备激活码") + @ApiImplicitParam(name = "params", value = "参数", required = true, dataType = "ApplicationCodeParams") + @PostMapping("/generateActivationCode") + public HttpResult generateActivationCode(@RequestBody ApplicationCodeParams params) { + String activationCode = activateService.generateActivationCode(params.getApplicationCode(), params.getPermanently()); + return HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), activationCode, ""); + } + + @ApiModel("生成设备激活码参数") + @Data + public static class ApplicationCodeParams { + @ApiModelProperty(value = "设备申请码", required = true) + private String applicationCode; + @ApiModelProperty(value = "是否永久激活", example = "1", required = true) + private int permanently; + } +} \ No newline at end of file diff --git a/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/service/ActivateService.java b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/service/ActivateService.java new file mode 100644 index 00000000..e3b2af08 --- /dev/null +++ b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/service/ActivateService.java @@ -0,0 +1,15 @@ +package com.njcn.gather.tool.active.service; + +public interface ActivateService { + + /** + * 生成设备激活码 + * + * @param applicationCode 申请码 + * @param permanently 是否永久激活 + * @return + */ + String generateActivationCode(String applicationCode, int permanently); + + +} diff --git a/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/service/impl/ActivateServiceImpl.java b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/service/impl/ActivateServiceImpl.java new file mode 100644 index 00000000..1dd1bc06 --- /dev/null +++ b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/service/impl/ActivateServiceImpl.java @@ -0,0 +1,65 @@ +package com.njcn.gather.tool.active.service.impl; + +import cn.hutool.json.JSONUtil; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.utils.RSAUtil; +import com.njcn.gather.tool.active.config.RSAProperties; +import com.njcn.gather.tool.active.service.ActivateService; +import com.njcn.gather.tool.active.vo.ActivationCodePlaintext; +import com.njcn.gather.tool.active.vo.ActivationModule; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Slf4j +@Service +public class ActivateServiceImpl implements ActivateService { + + private final RSAProperties rsaProperties; + + + @Override + public String generateActivationCode(String applicationCode, int permanently) { + // RSA 解密 + String plaintext; + try { + plaintext = RSAUtil.decrypt(applicationCode, RSAUtil.stringToPrivateKey(rsaProperties.getPrivateKey())); + } catch (Exception e) { + log.error("申请码解密失败", e); + throw new BusinessException(CommonResponseEnum.FAIL, "无效的申请码"); + } + ActivationCodePlaintext activationCodePlaintext = JSONUtil.toBean(plaintext, ActivationCodePlaintext.class); + if (activationCodePlaintext == null) { + log.error("申请码内容为空"); + throw new BusinessException(CommonResponseEnum.FAIL, "无效的申请码"); + } + // 激活码明文 + ActivationModule contrast = activationCodePlaintext.getContrast(); + ActivationModule simulate = activationCodePlaintext.getSimulate(); + ActivationModule digital = activationCodePlaintext.getDigital(); + if (contrast.isApply()) { + contrast.setPermanently(permanently); + activationCodePlaintext.setContrast(contrast); + } + if (simulate.isApply()) { + simulate.setPermanently(permanently); + activationCodePlaintext.setSimulate(simulate); + } + if (digital.isApply()) { + digital.setPermanently(permanently); + activationCodePlaintext.setDigital(digital); + } + // RSA 加密 + String jsonStr = JSONUtil.toJsonStr(activationCodePlaintext); + log.info("生成激活码明文:{}", jsonStr); + try { + return RSAUtil.encrypt(jsonStr, RSAUtil.stringToPublicKey(rsaProperties.getPublicKey())); + } catch (Exception e) { + log.error("生成激活码失败", e); + throw new BusinessException(CommonResponseEnum.FAIL, "生成激活码失败"); + } + } + +} diff --git a/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ActivationCodePlaintext.java b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ActivationCodePlaintext.java new file mode 100644 index 00000000..f01a08f4 --- /dev/null +++ b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ActivationCodePlaintext.java @@ -0,0 +1,28 @@ +package com.njcn.gather.tool.active.vo; + +import lombok.Data; + +@Data +public class ActivationCodePlaintext { + /** + * mac地址 + */ + private String macAddress; + + /** + * 模拟式模块 + */ + private ActivationModule simulate; + + /** + * 数字式模块 + */ + private ActivationModule digital; + + /** + * 比对式模块 + */ + private ActivationModule contrast; + + +} diff --git a/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ActivationModule.java b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ActivationModule.java new file mode 100644 index 00000000..72348ca0 --- /dev/null +++ b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ActivationModule.java @@ -0,0 +1,15 @@ +package com.njcn.gather.tool.active.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class ActivationModule extends ApplicationModule { + /** + * 是否永久授权 + */ + private int permanently; + + +} \ No newline at end of file diff --git a/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ApplicationCodePlaintext.java b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ApplicationCodePlaintext.java new file mode 100644 index 00000000..de03d39a --- /dev/null +++ b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ApplicationCodePlaintext.java @@ -0,0 +1,28 @@ +package com.njcn.gather.tool.active.vo; + +import lombok.Data; + +@Data +public class ApplicationCodePlaintext { + /** + * mac地址 + */ + private String macAddress; + + /** + * 模拟式模块 + */ + private ApplicationModule simulate; + + /** + * 数字式模块 + */ + private ApplicationModule digital; + + /** + * 比对式模块 + */ + private ApplicationModule contrast; + + +} diff --git a/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ApplicationModule.java b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ApplicationModule.java new file mode 100644 index 00000000..a11876b2 --- /dev/null +++ b/tools/activate-tool/src/main/java/com/njcn/gather/tool/active/vo/ApplicationModule.java @@ -0,0 +1,15 @@ +package com.njcn.gather.tool.active.vo; + +import lombok.Data; + +@Data +public class ApplicationModule { + /** + * 是否申请 1是 0否 + */ + private Integer apply; + + public boolean isApply() { + return apply == 1; + } +} \ No newline at end of file diff --git a/tools/activate-tool/src/main/resources/application.yml b/tools/activate-tool/src/main/resources/application.yml new file mode 100644 index 00000000..3e3b7eb2 --- /dev/null +++ b/tools/activate-tool/src/main/resources/application.yml @@ -0,0 +1,8 @@ +server: + port: 8888 +spring: + application: + name: active-tool +rsa: + private-key: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcUyYhVqczGxblL+o/xZzF/8nf+LjrfUE/dS1aRHM7uMDD0cgCArhjtfneFePrMxt+Z7W8yNBzSarub8qsfhaVNikV7Es7oaeTygfjQXTi2n4AFkir3fM07J08RpWhl5M8f8uWTCuvFUYAw00gq55typqmnbkmJa2VIUy/iQf+cMCP7abz4/jNhUzUR3qA7TV4oMRgTdIEDUp63YF8dOC+JH8XxYrCVeHXV6fLCwmesdMzl0lB2VTEKMfLbXhOmF5g7P9y/16VCcN8UBuZlbyYfn+GAxJOSbeHi5HshOKfoSuD7Jz+3WQZpNavOWjIFExKIU38/CvnJCOP7XBCqpSTAgMBAAECggEAYeWokWRE3TpvwiOZnUpR/aVMdVi75a3ROL5XIpqPV61B+t/bU3cEpl0GF9C5pUeiRi0IoStZb3mI9D1KPW/REKyUWkhabQO1gFYbTnRlkNOn6MILzKX4cwJjDaZeeo4EBPU7N+qHyOOXrU6hdH5FfxhMdV983ajm5eeuupxER1C2kAcIklTeVpTX6EKOgZb5LBp5ssOVm2P42pOauvcRozRcvZmqnErXmukv0H4l3EVNt4rHpTn9riHUC63e8JfiYzVaF6zuNUxv6nHEft0/SRMw11XSTnNfDzcKqgjz6ksFBS/6eQQYKESk+ONC53HUuYHFAknkwsPupDCT2W8FIQKBgQDLHT/xCU3nxGr4vFKBDNaO2D5oK20ECbBO4oDvLWWmQG7f+6TsMy8PgVdMnoL4RfqGlwFAKEpS6KVFHnBVqnNEhcdy9uCI7x7Xx8UnyUtxj1EDTm76uta9Ki9OrlqB6tImDM9+Ya3vGktW37ht4WOx2OsJRhG1dbf6RLwFlH7DWwKBgQDFBxvi5I1BR6hg6Tj7xd2SqOT2Y+BED3xuSYENhWbmMhLJDResaB7mjztbxlYaY2mOE0holWm2uDmVFFhMh4jYXik4hYH8nmDzq9mDpZCZ9pyjYqnAP8THoAa8EbgrUWB8A6BPH4iL3KbMnBfBKY0pIr2xrvnjQjNBAgta7KDRKQKBgCe6oe4wxrdF2TKsC2tIqpMoQxS3Icy/ZGgZr+SYuaBKTCWtoDW/UT40K3JGMxIDBhzbXphBCUCsVt9tM8Xd4EwP6tJW7dZ7B0pnve2pVwNwaAVAiz6p2yUHIle+jN+Koe5lZRSwYIg7WW81tWpwwsJfzqFyvjYDP6hJV4mz4ROvAoGAaRcdnKvjXApomShMqJ4lTPChD3q+SA8qg3jZSOj6tZXHx00gb2kp8jg7pPvpOTIFPy6x1Ha9aCRjMk0ju84fA6lVuzwa1S907wOehUVuF3Eeo1cgy9Y3k3KbpPyeixxgpkUY4JslLdSHc2NemD0dee951qhJyRmqVOZOQDUuoeECgYEAqBw2cAFk3vM97WY06TSldGA8ajVHx3BYRjj+zl62NTQthy8fw3tqxb3c5e8toOmZWKjZvDhg2TRLhsDDQWEYg3LZG87REqVIjgEPcpjNLidjygGX8n3JF2o0O5I/EMvl0s/+LVQONfduOBvhwDqr8QNisbLsyneiAq7umewMolo=" + public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnFMmIVanMxsW5S/qP8Wcxf/J3/i4631BP3UtWkRzO7jAw9HIAgK4Y7X53hXj6zMbfme1vMjQc0mq7m/KrH4WlTYpFexLO6Gnk8oH40F04tp+ABZIq93zNOydPEaVoZeTPH/LlkwrrxVGAMNNIKuebcqapp25JiWtlSFMv4kH/nDAj+2m8+P4zYVM1Ed6gO01eKDEYE3SBA1Ket2BfHTgviR/F8WKwlXh11enywsJnrHTM5dJQdlUxCjHy214TpheYOz/cv9elQnDfFAbmZW8mH5/hgMSTkm3h4uR7ITin6Erg+yc/t1kGaTWrzloyBRMSiFN/Pwr5yQjj+1wQqqUkwIDAQAB" \ No newline at end of file diff --git a/tools/pom.xml b/tools/pom.xml index 68751820..a909ada9 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -18,6 +18,7 @@ report-generator wave-comtrade + activate-tool \ No newline at end of file