From 9f6b8efb51daee7d3351b1f3ea8d9d5b9b0e5f6c Mon Sep 17 00:00:00 2001 From: caiyuchao Date: Tue, 15 Apr 2025 10:25:43 +0800 Subject: [PATCH] init project --- .gitignore | 88 ++++++ README.md | 5 + pom.xml | 178 ++++++++++++ .../wfc/common/license/ServeApplication.java | 18 ++ .../common/config/RestTemplateConfig.java | 81 ++++++ .../common/utils/SpringContextUtils.java | 76 +++++ .../controller/LicenseCreatorController.java | 139 +++++++++ .../license/domain/LicenseCheckModel.java | 73 +++++ .../license/domain/LicenseCreatorParam.java | 189 +++++++++++++ .../license/domain/LicenseGenParam.java | 107 +++++++ .../license/license/AbstractServerInfos.java | 122 ++++++++ .../license/license/CustomKeyStoreParam.java | 60 ++++ .../license/license/CustomLicenseManager.java | 264 ++++++++++++++++++ .../license/license/LicenseCreator.java | 93 ++++++ .../license/license/LinuxServerInfos.java | 86 ++++++ .../license/license/WindowsServerInfos.java | 144 ++++++++++ src/main/resources/application.properties | 10 + src/main/resources/banner.txt | 23 ++ src/main/resources/privateKeys.keystore | Bin 0 -> 1285 bytes 19 files changed, 1756 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/org/wfc/common/license/ServeApplication.java create mode 100644 src/main/java/org/wfc/common/license/common/config/RestTemplateConfig.java create mode 100644 src/main/java/org/wfc/common/license/common/utils/SpringContextUtils.java create mode 100644 src/main/java/org/wfc/common/license/controller/LicenseCreatorController.java create mode 100644 src/main/java/org/wfc/common/license/domain/LicenseCheckModel.java create mode 100644 src/main/java/org/wfc/common/license/domain/LicenseCreatorParam.java create mode 100644 src/main/java/org/wfc/common/license/domain/LicenseGenParam.java create mode 100644 src/main/java/org/wfc/common/license/license/AbstractServerInfos.java create mode 100644 src/main/java/org/wfc/common/license/license/CustomKeyStoreParam.java create mode 100644 src/main/java/org/wfc/common/license/license/CustomLicenseManager.java create mode 100644 src/main/java/org/wfc/common/license/license/LicenseCreator.java create mode 100644 src/main/java/org/wfc/common/license/license/LinuxServerInfos.java create mode 100644 src/main/java/org/wfc/common/license/license/WindowsServerInfos.java create mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/banner.txt create mode 100644 src/main/resources/privateKeys.keystore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e5d2e37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,88 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp +*.bak +tmp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml + +# docker +docker/mysql/data +docker/redis/data +docker/mysql/log +docker/nacos/logs +docker/mysql/db/*.sql +docker/wfc/*/jar/*.jar +docker/wfc/*/*/jar/*.jar + +# Logs +logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +!.vscode/settings.json +!.vscode/launch.json +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +package-lock.json +yarn.lock + +.VSCodeCounter diff --git a/README.md b/README.md new file mode 100644 index 0000000..545d0a8 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# license服务 + +## 项目介绍 + +用于生成licese.lic文件,提供给用户的访问许可证明 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c056143 --- /dev/null +++ b/pom.xml @@ -0,0 +1,178 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.0.RELEASE + + + + com.modules + cloud-license-serve + 1.0.0 + cloud-license-serve + license serve project + + + 1.8 + Hoxton.SR3 + + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + org.projectlombok + lombok + + + + + de.schlichtherle.truelicense + truelicense-core + 1.33 + + + + net.sourceforge.nekohtml + nekohtml + 1.9.18 + + + + + org.apache.commons + commons-lang3 + 3.7 + + + + commons-io + commons-io + 2.6 + + + commons-codec + commons-codec + 1.11 + + + + + org.apache.httpcomponents + httpclient + 4.5.5 + + + + + com.alibaba + fastjson + 1.2.47 + + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + true + + + + + + diff --git a/src/main/java/org/wfc/common/license/ServeApplication.java b/src/main/java/org/wfc/common/license/ServeApplication.java new file mode 100644 index 0000000..ca8c54d --- /dev/null +++ b/src/main/java/org/wfc/common/license/ServeApplication.java @@ -0,0 +1,18 @@ +package org.wfc.common.license; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletComponentScan; + +@Slf4j +@SpringBootApplication +@ServletComponentScan +public class ServeApplication { + + public static void main(String[] args) { + log.info("启动开始"); + SpringApplication.run(ServeApplication.class, args); + log.info("启动成功"); + } +} diff --git a/src/main/java/org/wfc/common/license/common/config/RestTemplateConfig.java b/src/main/java/org/wfc/common/license/common/config/RestTemplateConfig.java new file mode 100644 index 0000000..59592f1 --- /dev/null +++ b/src/main/java/org/wfc/common/license/common/config/RestTemplateConfig.java @@ -0,0 +1,81 @@ +package org.wfc.common.license.common.config; + +import org.apache.http.Header; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeader; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Configuration +public class RestTemplateConfig { + + /** + * 返回RestTemplate + * + * @param factory ClientHttpRequestFactory + * @return RestTemplate + */ + @Bean + public RestTemplate restTemplate(ClientHttpRequestFactory factory) { + return new RestTemplate(factory); + } + + + /** + * ClientHttpRequestFactory接口的另一种实现方式(推荐使用),即: + * HttpComponentsClientHttpRequestFactory:底层使用Httpclient连接池的方式创建Http连接请求 + * + * @return HttpComponentsClientHttpRequestFactory + */ + @Bean + public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory() { + //Httpclient连接池,长连接保持30秒 + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS); + + //设置总连接数 + connectionManager.setMaxTotal(1000); + //设置同路由的并发数 + connectionManager.setDefaultMaxPerRoute(1000); + + //设置header + List
headers = new ArrayList
(); + headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04")); + headers.add(new BasicHeader("Accept-Encoding", "gzip, deflate")); + headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3")); + headers.add(new BasicHeader("Connection", "keep-alive")); + + //创建HttpClient + HttpClient httpClient = HttpClientBuilder.create() + .setConnectionManager(connectionManager) + .setDefaultHeaders(headers) + .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) //设置重试次数 + .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) //设置保持长连接 + .build(); + + //创建HttpComponentsClientHttpRequestFactory实例 + HttpComponentsClientHttpRequestFactory requestFactory = + new HttpComponentsClientHttpRequestFactory(httpClient); + + //设置客户端和服务端建立连接的超时时间 + requestFactory.setConnectTimeout(5000); + //设置客户端从服务端读取数据的超时时间 + requestFactory.setReadTimeout(5000); + //设置从连接池获取连接的超时时间,不宜过长 + requestFactory.setConnectionRequestTimeout(200); + //缓冲请求数据,默认为true。通过POST或者PUT大量发送数据时,建议将此更改为false,以免耗尽内存 + requestFactory.setBufferRequestBody(false); + return requestFactory; + } + +} diff --git a/src/main/java/org/wfc/common/license/common/utils/SpringContextUtils.java b/src/main/java/org/wfc/common/license/common/utils/SpringContextUtils.java new file mode 100644 index 0000000..daccaf2 --- /dev/null +++ b/src/main/java/org/wfc/common/license/common/utils/SpringContextUtils.java @@ -0,0 +1,76 @@ +package org.wfc.common.license.common.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * 自定义Spring工具类 + */ +@Component +public class SpringContextUtils implements ApplicationContextAware { + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException { + applicationContext = context; + } + + /** + * 获取ApplicationContext对象 + * + * @return + */ + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + /** + * 根据bean的名称获取bean + * + * @param name + * @return + */ + public static Object getBeanByName(String name) { + return applicationContext.getBean(name); + } + + /** + * 根据bean的class来查找对象 + * + * @param + * @param c + * @return + */ + public static T getBeanByClass(Class c) { + return applicationContext.getBean(c); + } + + /** + * 根据bean的class来查找所有的对象(包括子类) + * + * @param + * @param c + * @return + */ + public static Map getBeansByClass(Class c) { + return applicationContext.getBeansOfType(c); + } + + /** + * 获取HttpServletRequest + * + * @return + */ + public static HttpServletRequest getRequest() { + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = attributes.getRequest(); + return request; + } +} diff --git a/src/main/java/org/wfc/common/license/controller/LicenseCreatorController.java b/src/main/java/org/wfc/common/license/controller/LicenseCreatorController.java new file mode 100644 index 0000000..833d24b --- /dev/null +++ b/src/main/java/org/wfc/common/license/controller/LicenseCreatorController.java @@ -0,0 +1,139 @@ +package org.wfc.common.license.controller; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +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 org.wfc.common.license.domain.LicenseCheckModel; +import org.wfc.common.license.domain.LicenseCreatorParam; +import org.wfc.common.license.domain.LicenseGenParam; +import org.wfc.common.license.license.AbstractServerInfos; +import org.wfc.common.license.license.LicenseCreator; +import org.wfc.common.license.license.LinuxServerInfos; +import org.wfc.common.license.license.WindowsServerInfos; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 用于生成证书文件,不能放在给客户部署的代码里 + * + * @since 1.0.0 + */ +@RestController +@RequestMapping("/license") +public class LicenseCreatorController { + + /** + * 证书生成路径 + */ + @Value("${license.licensePath}") + private String licensePath; + + /** + * 获取服务器硬件信息 + * + * @param osName 操作系统类型,如果为空则自动判断 + * @return com.ccx.models.license.LicenseCheckModel + */ + @RequestMapping(value = "/getServerInfos", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}) + public LicenseCheckModel getServerInfos(@RequestParam(value = "osName", required = false) String osName) { + //操作系统类型 + if (StringUtils.isBlank(osName)) { + osName = System.getProperty("os.name"); + } + osName = osName.toLowerCase(); + + AbstractServerInfos abstractServerInfos = null; + + //根据不同操作系统类型选择不同的数据获取方法 + if (osName.startsWith("windows")) { + abstractServerInfos = new WindowsServerInfos(); + } else if (osName.startsWith("linux")) { + abstractServerInfos = new LinuxServerInfos(); + } else {//其他服务器类型 + abstractServerInfos = new LinuxServerInfos(); + } + return abstractServerInfos.getServerInfos(); + } + + /** + * 生成证书2 + * + * @param param 生成证书需要的参数,如:{"subject":"ccx-models","privateAlias":"privateKey","keyPass":"5T7Zz5Y0dJFcqTxvzkH5LDGJJSGMzQ","storePass":"3538cef8e7","licensePath":"C:/Users/zifangsky/Desktop/license.lic","privateKeysStorePath":"C:/Users/zifangsky/Desktop/privateKeys.keystore","issuedTime":"2018-04-26 14:48:12","expiryTime":"2018-12-31 00:00:00","consumerType":"User","consumerAmount":1,"description":"这是证书描述信息","licenseCheckModel":{"ipAddress":["192.168.245.1","10.0.5.22"],"macAddress":["00-50-56-C0-00-01","50-7B-9D-F9-18-41"],"cpuSerial":"BFEBFBFF000406E3","mainBoardSerial":"L1HF65E00X9"}} + * @return java.util.Map + */ + @RequestMapping(value = "/generateLicense2", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}) + public Map generateLicense2(@RequestBody LicenseCreatorParam param) { + Map resultMap = new HashMap<>(2); + + if (StringUtils.isBlank(param.getLicensePath())) { + param.setLicensePath(licensePath); + } + + LicenseCreator licenseCreator = new LicenseCreator(param); + boolean result = licenseCreator.generateLicense(); + + if (result) { + resultMap.put("result", "ok"); + resultMap.put("msg", param); + } else { + resultMap.put("result", "error"); + resultMap.put("msg", "证书文件生成失败!"); + } + return resultMap; + } + + /** + * 生成证书 + * + * @param param 生成证书需要的参数 + * @return java.util.Map + */ + @RequestMapping(value = "/generateLicense", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}) + public Map generateLicense(@RequestBody LicenseGenParam genParam) { + Map resultMap = new HashMap<>(2); + + LicenseCreatorParam param = new LicenseCreatorParam(); + param.setSubject("license_wfc"); + param.setPrivateAlias("privateKey"); + param.setKeyPass("wanfi_wfc_Admin123lic"); + param.setStorePass("public_wfc_Admin123"); + if (StringUtils.isBlank(genParam.getLicensePath())) { + param.setLicensePath(licensePath); + } else { + param.setLicensePath(genParam.getLicensePath()); + } + // 相对路径resources资源目录 + String resourcePath = getClass().getClassLoader().getResource("").getPath(); + param.setPrivateKeysStorePath(resourcePath + "privateKeys.keystore"); +// param.setPrivateKeysStorePath("D:\\projects\\testdir\\spring-boot2-license\\cloud-license-serve\\target\\classes\\privateCerts.keystore"); + param.setIssuedTime(new Date()); + param.setExpiryTime(genParam.getExpiryTime()); + param.setConsumerType("user"); + param.setConsumerAmount(1); + param.setDescription("这是证书描述信息"); + LicenseCheckModel licenseCheckModel = new LicenseCheckModel(); + licenseCheckModel.setIpAddress(genParam.getIpAddress()); + licenseCheckModel.setMacAddress(genParam.getMacAddress()); + licenseCheckModel.setCpuSerial(genParam.getCpuSerial()); + licenseCheckModel.setMainBoardSerial(genParam.getMainBoardSerial()); + param.setLicenseCheckModel(licenseCheckModel); + + LicenseCreator licenseCreator = new LicenseCreator(param); + boolean result = licenseCreator.generateLicense(); + + if (result) { + resultMap.put("result", "ok"); + resultMap.put("msg", genParam); + } else { + resultMap.put("result", "error"); + resultMap.put("msg", "证书文件生成失败!"); + } + return resultMap; + } +} diff --git a/src/main/java/org/wfc/common/license/domain/LicenseCheckModel.java b/src/main/java/org/wfc/common/license/domain/LicenseCheckModel.java new file mode 100644 index 0000000..5786c69 --- /dev/null +++ b/src/main/java/org/wfc/common/license/domain/LicenseCheckModel.java @@ -0,0 +1,73 @@ +package org.wfc.common.license.domain; + +import java.io.Serializable; +import java.util.List; + +/** + * 自定义需要校验的License参数 + */ +public class LicenseCheckModel implements Serializable { + + private static final long serialVersionUID = 8600137500316662317L; + /** + * 可被允许的IP地址 + */ + private List ipAddress; + + /** + * 可被允许的MAC地址 + */ + private List macAddress; + + /** + * 可被允许的CPU序列号 + */ + private String cpuSerial; + + /** + * 可被允许的主板序列号 + */ + private String mainBoardSerial; + + public List getIpAddress() { + return ipAddress; + } + + public void setIpAddress(List ipAddress) { + this.ipAddress = ipAddress; + } + + public List getMacAddress() { + return macAddress; + } + + public void setMacAddress(List macAddress) { + this.macAddress = macAddress; + } + + public String getCpuSerial() { + return cpuSerial; + } + + public void setCpuSerial(String cpuSerial) { + this.cpuSerial = cpuSerial; + } + + public String getMainBoardSerial() { + return mainBoardSerial; + } + + public void setMainBoardSerial(String mainBoardSerial) { + this.mainBoardSerial = mainBoardSerial; + } + + @Override + public String toString() { + return "LicenseCheckModel{" + + "ipAddress=" + ipAddress + + ", macAddress=" + macAddress + + ", cpuSerial='" + cpuSerial + '\'' + + ", mainBoardSerial='" + mainBoardSerial + '\'' + + '}'; + } +} diff --git a/src/main/java/org/wfc/common/license/domain/LicenseCreatorParam.java b/src/main/java/org/wfc/common/license/domain/LicenseCreatorParam.java new file mode 100644 index 0000000..0b48c98 --- /dev/null +++ b/src/main/java/org/wfc/common/license/domain/LicenseCreatorParam.java @@ -0,0 +1,189 @@ +package org.wfc.common.license.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serializable; +import java.util.Date; + +/** + * License生成类需要的参数 + */ +public class LicenseCreatorParam implements Serializable { + + private static final long serialVersionUID = -7793154252684580872L; + /** + * 证书subject + */ + private String subject; + + /** + * 密钥别称 + */ + private String privateAlias; + + /** + * 密钥密码(需要妥善保管,不能让使用者知道) + */ + private String keyPass; + + /** + * 访问秘钥库的密码 + */ + private String storePass; + + /** + * 证书生成路径 + */ + private String licensePath; + + /** + * 密钥库存储路径 + */ + private String privateKeysStorePath; + + /** + * 证书生效时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date issuedTime = new Date(); + + /** + * 证书失效时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date expiryTime; + + /** + * 用户类型 + */ + private String consumerType = "user"; + + /** + * 用户数量 + */ + private Integer consumerAmount = 1; + + /** + * 描述信息 + */ + private String description = ""; + + /** + * 额外的服务器硬件校验信息 + */ + private LicenseCheckModel licenseCheckModel; + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getPrivateAlias() { + return privateAlias; + } + + public void setPrivateAlias(String privateAlias) { + this.privateAlias = privateAlias; + } + + public String getKeyPass() { + return keyPass; + } + + public void setKeyPass(String keyPass) { + this.keyPass = keyPass; + } + + public String getStorePass() { + return storePass; + } + + public void setStorePass(String storePass) { + this.storePass = storePass; + } + + public String getLicensePath() { + return licensePath; + } + + public void setLicensePath(String licensePath) { + this.licensePath = licensePath; + } + + public String getPrivateKeysStorePath() { + return privateKeysStorePath; + } + + public void setPrivateKeysStorePath(String privateKeysStorePath) { + this.privateKeysStorePath = privateKeysStorePath; + } + + public Date getIssuedTime() { + return issuedTime; + } + + public void setIssuedTime(Date issuedTime) { + this.issuedTime = issuedTime; + } + + public Date getExpiryTime() { + return expiryTime; + } + + public void setExpiryTime(Date expiryTime) { + this.expiryTime = expiryTime; + } + + public String getConsumerType() { + return consumerType; + } + + public void setConsumerType(String consumerType) { + this.consumerType = consumerType; + } + + public Integer getConsumerAmount() { + return consumerAmount; + } + + public void setConsumerAmount(Integer consumerAmount) { + this.consumerAmount = consumerAmount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LicenseCheckModel getLicenseCheckModel() { + return licenseCheckModel; + } + + public void setLicenseCheckModel(LicenseCheckModel licenseCheckModel) { + this.licenseCheckModel = licenseCheckModel; + } + + @Override + public String toString() { + return "LicenseCreatorParam{" + + "subject='" + subject + '\'' + + ", privateAlias='" + privateAlias + '\'' + + ", keyPass='" + keyPass + '\'' + + ", storePass='" + storePass + '\'' + + ", licensePath='" + licensePath + '\'' + + ", privateKeysStorePath='" + privateKeysStorePath + '\'' + + ", issuedTime=" + issuedTime + + ", expiryTime=" + expiryTime + + ", consumerType='" + consumerType + '\'' + + ", consumerAmount=" + consumerAmount + + ", description='" + description + '\'' + + ", licenseCheckModel=" + licenseCheckModel + + '}'; + } +} diff --git a/src/main/java/org/wfc/common/license/domain/LicenseGenParam.java b/src/main/java/org/wfc/common/license/domain/LicenseGenParam.java new file mode 100644 index 0000000..89c7996 --- /dev/null +++ b/src/main/java/org/wfc/common/license/domain/LicenseGenParam.java @@ -0,0 +1,107 @@ +package org.wfc.common.license.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * License生成类需要的参数 + */ +public class LicenseGenParam implements Serializable { + + private static final long serialVersionUID = -7793154252684580871L; + + /** + * 证书生成路径 + */ + private String licensePath; + + /** + * 证书失效时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date expiryTime; + + /** + * 额外的服务器硬件校验信息 + */ + private LicenseCheckModel licenseCheckModel; + + /** + * 可被允许的IP地址 + */ + private List ipAddress; + + /** + * 可被允许的MAC地址 + */ + private List macAddress; + + /** + * 可被允许的CPU序列号 + */ + private String cpuSerial; + + /** + * 可被允许的主板序列号 + */ + private String mainBoardSerial; + + public String getLicensePath() { + return licensePath; + } + + public void setLicensePath(String licensePath) { + this.licensePath = licensePath; + } + + public Date getExpiryTime() { + return expiryTime; + } + + public void setExpiryTime(Date expiryTime) { + this.expiryTime = expiryTime; + } + + public LicenseCheckModel getLicenseCheckModel() { + return licenseCheckModel; + } + + public void setLicenseCheckModel(LicenseCheckModel licenseCheckModel) { + this.licenseCheckModel = licenseCheckModel; + } + + public List getIpAddress() { + return ipAddress; + } + + public void setIpAddress(List ipAddress) { + this.ipAddress = ipAddress; + } + + public List getMacAddress() { + return macAddress; + } + + public void setMacAddress(List macAddress) { + this.macAddress = macAddress; + } + + public String getCpuSerial() { + return cpuSerial; + } + + public void setCpuSerial(String cpuSerial) { + this.cpuSerial = cpuSerial; + } + + public String getMainBoardSerial() { + return mainBoardSerial; + } + + public void setMainBoardSerial(String mainBoardSerial) { + this.mainBoardSerial = mainBoardSerial; + } +} diff --git a/src/main/java/org/wfc/common/license/license/AbstractServerInfos.java b/src/main/java/org/wfc/common/license/license/AbstractServerInfos.java new file mode 100644 index 0000000..0f758f3 --- /dev/null +++ b/src/main/java/org/wfc/common/license/license/AbstractServerInfos.java @@ -0,0 +1,122 @@ +package org.wfc.common.license.license; + +import org.wfc.common.license.domain.LicenseCheckModel; +import lombok.extern.slf4j.Slf4j; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** + * 用于获取客户服务器的基本信息,如:IP、Mac地址、CPU序列号、主板序列号等 + */ +@Slf4j +public abstract class AbstractServerInfos { + + /** + * 组装需要额外校验的License参数 + * + * @return demo.LicenseCheckModel + * @since 1.0.0 + */ + public LicenseCheckModel getServerInfos() { + LicenseCheckModel result = new LicenseCheckModel(); + + try { + result.setIpAddress(this.getIpAddress()); + result.setMacAddress(this.getMacAddress()); + result.setCpuSerial(this.getCPUSerial()); + result.setMainBoardSerial(this.getMainBoardSerial()); + } catch (Exception e) { + log.error("获取服务器硬件信息失败", e); + } + + return result; + } + + /** + * 获取IP地址 + * + * @return java.util.List + */ + protected abstract List getIpAddress() throws Exception; + + /** + * 获取Mac地址 + * + * @return java.util.List + */ + protected abstract List getMacAddress() throws Exception; + + /** + * 获取CPU序列号 + * + * @return java.lang.String + */ + protected abstract String getCPUSerial() throws Exception; + + /** + * 获取主板序列号 + * + * @return java.lang.String + */ + protected abstract String getMainBoardSerial() throws Exception; + + /** + * 获取当前服务器所有符合条件的InetAddress + * + * @return java.util.List + */ + protected List getLocalAllInetAddress() throws Exception { + List result = new ArrayList<>(4); + + // 遍历所有的网络接口 + for (Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements(); ) { + NetworkInterface iface = (NetworkInterface) networkInterfaces.nextElement(); + // 在所有的接口下再遍历IP + for (Enumeration inetAddresses = iface.getInetAddresses(); inetAddresses.hasMoreElements(); ) { + InetAddress inetAddr = (InetAddress) inetAddresses.nextElement(); + + //排除LoopbackAddress、SiteLocalAddress、LinkLocalAddress、MulticastAddress类型的IP地址 + if (!inetAddr.isLoopbackAddress() /*&& !inetAddr.isSiteLocalAddress()*/ + && !inetAddr.isLinkLocalAddress() && !inetAddr.isMulticastAddress()) { + result.add(inetAddr); + } + } + } + return result; + } + + /** + * 获取某个网络接口的Mac地址 + * + * @param + * @return void + */ + protected String getMacByInetAddress(InetAddress inetAddr) { + try { + byte[] mac = NetworkInterface.getByInetAddress(inetAddr).getHardwareAddress(); + StringBuffer stringBuffer = new StringBuffer(); + for (int i = 0; i < mac.length; i++) { + if (i != 0) { + stringBuffer.append("-"); + } + //将十六进制byte转化为字符串 + String temp = Integer.toHexString(mac[i] & 0xff); + if (temp.length() == 1) { + stringBuffer.append("0" + temp); + } else { + stringBuffer.append(temp); + } + } + return stringBuffer.toString().toUpperCase(); + } catch (SocketException e) { + e.printStackTrace(); + log.error("获取某个网络接口的Mac地址异常", e.getMessage()); + } + return null; + } +} diff --git a/src/main/java/org/wfc/common/license/license/CustomKeyStoreParam.java b/src/main/java/org/wfc/common/license/license/CustomKeyStoreParam.java new file mode 100644 index 0000000..a28faf4 --- /dev/null +++ b/src/main/java/org/wfc/common/license/license/CustomKeyStoreParam.java @@ -0,0 +1,60 @@ +package org.wfc.common.license.license; + +import de.schlichtherle.license.AbstractKeyStoreParam; + +import java.io.*; + +/** + * 自定义KeyStoreParam,用于将公私钥存储文件存放到其他磁盘位置而不是项目中 + */ +public class CustomKeyStoreParam extends AbstractKeyStoreParam { + + /** + * 公钥/私钥在磁盘上的存储路径 + */ + private String storePath; + private String alias; + private String storePwd; + private String keyPwd; + + public CustomKeyStoreParam(Class clazz, String resource, String alias, String storePwd, String keyPwd) { + super(clazz, resource); + this.storePath = resource; + this.alias = alias; + this.storePwd = storePwd; + this.keyPwd = keyPwd; + } + + + @Override + public String getAlias() { + return alias; + } + + @Override + public String getStorePwd() { + return storePwd; + } + + @Override + public String getKeyPwd() { + return keyPwd; + } + + /** + * 复写de.schlichtherle.license.AbstractKeyStoreParam的getStream()方法
+ * 用于将公私钥存储文件存放到其他磁盘位置而不是项目中 + * + * @param + * @return java.io.InputStream + */ + @Override + public InputStream getStream() throws IOException { + final InputStream in = new FileInputStream(new File(storePath)); + if (null == in) { + throw new FileNotFoundException(storePath); + } + + return in; + } +} diff --git a/src/main/java/org/wfc/common/license/license/CustomLicenseManager.java b/src/main/java/org/wfc/common/license/license/CustomLicenseManager.java new file mode 100644 index 0000000..c4ae323 --- /dev/null +++ b/src/main/java/org/wfc/common/license/license/CustomLicenseManager.java @@ -0,0 +1,264 @@ +package org.wfc.common.license.license; + +import org.wfc.common.license.domain.LicenseCheckModel; +import de.schlichtherle.license.*; +import de.schlichtherle.xml.GenericCertificate; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.beans.XMLDecoder; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.util.List; + +/** + * 自定义LicenseManager,用于增加额外的服务器硬件信息校验 + */ +@Slf4j +public class CustomLicenseManager extends LicenseManager { + + //XML编码 + private static final String XML_CHARSET = "UTF-8"; + //默认BUFSIZE + private static final int DEFAULT_BUFSIZE = 8 * 1024; + + public CustomLicenseManager() { + + } + + public CustomLicenseManager(LicenseParam param) { + super(param); + } + + /** + * 复写create方法 + * + * @param + * @return byte[] + */ + @Override + protected synchronized byte[] create( + LicenseContent content, + LicenseNotary notary) + throws Exception { + initialize(content); + this.validateCreate(content); + final GenericCertificate certificate = notary.sign(content); + return getPrivacyGuard().cert2key(certificate); + } + + /** + * 复写install方法,其中validate方法调用本类中的validate方法,校验IP地址、Mac地址等其他信息 + * + * @param + * @return de.schlichtherle.license.LicenseContent + */ + @Override + protected synchronized LicenseContent install( + final byte[] key, + final LicenseNotary notary) + throws Exception { + final GenericCertificate certificate = getPrivacyGuard().key2cert(key); + + notary.verify(certificate); + final LicenseContent content = (LicenseContent) this.load(certificate.getEncoded()); + this.validate(content); + setLicenseKey(key); + setCertificate(certificate); + + return content; + } + + /** + * 复写verify方法,调用本类中的validate方法,校验IP地址、Mac地址等其他信息 + * + * @param + * @return de.schlichtherle.license.LicenseContent + */ + @Override + protected synchronized LicenseContent verify(final LicenseNotary notary) + throws Exception { + GenericCertificate certificate = getCertificate(); + + // Load license key from preferences, + final byte[] key = getLicenseKey(); + if (null == key) { + throw new NoLicenseInstalledException(getLicenseParam().getSubject()); + } + + certificate = getPrivacyGuard().key2cert(key); + notary.verify(certificate); + final LicenseContent content = (LicenseContent) this.load(certificate.getEncoded()); + this.validate(content); + setCertificate(certificate); + + return content; + } + + /** + * 校验生成证书的参数信息 + * + * @param content 证书正文 + */ + protected synchronized void validateCreate(final LicenseContent content) + throws LicenseContentException { + final LicenseParam param = getLicenseParam(); + + final Date now = new Date(); + final Date notBefore = content.getNotBefore(); + final Date notAfter = content.getNotAfter(); + if (null != notAfter && now.after(notAfter)) { + throw new LicenseContentException("证书失效时间不能早于当前时间"); + } + if (null != notBefore && null != notAfter && notAfter.before(notBefore)) { + throw new LicenseContentException("证书生效时间不能晚于证书失效时间"); + } + final String consumerType = content.getConsumerType(); + if (null == consumerType) { + throw new LicenseContentException("用户类型不能为空"); + } + } + + + /** + * 复写validate方法,增加IP地址、Mac地址等其他信息校验 + * + * @param content LicenseContent + */ + @Override + protected synchronized void validate(final LicenseContent content) + throws LicenseContentException { + //1. 首先调用父类的validate方法 + super.validate(content); + + //2. 然后校验自定义的License参数 + //License中可被允许的参数信息 + LicenseCheckModel expectedCheckModel = (LicenseCheckModel) content.getExtra(); + //当前服务器真实的参数信息 + LicenseCheckModel serverCheckModel = getServerInfos(); + + if (expectedCheckModel != null && serverCheckModel != null) { + //校验IP地址 + if (!checkIpAddress(expectedCheckModel.getIpAddress(), serverCheckModel.getIpAddress())) { + throw new LicenseContentException("当前服务器的IP没在授权范围内"); + } + + //校验Mac地址 + if (!checkIpAddress(expectedCheckModel.getMacAddress(), serverCheckModel.getMacAddress())) { + throw new LicenseContentException("当前服务器的Mac地址没在授权范围内"); + } + + //校验主板序列号 + if (!checkSerial(expectedCheckModel.getMainBoardSerial(), serverCheckModel.getMainBoardSerial())) { + throw new LicenseContentException("当前服务器的主板序列号没在授权范围内"); + } + + //校验CPU序列号 + if (!checkSerial(expectedCheckModel.getCpuSerial(), serverCheckModel.getCpuSerial())) { + throw new LicenseContentException("当前服务器的CPU序列号没在授权范围内"); + } + } else { + throw new LicenseContentException("不能获取服务器硬件信息"); + } + } + + + /** + * 重写XMLDecoder解析XML + * + * @param encoded XML类型字符串 + * @return java.lang.Object + */ + private Object load(String encoded) { + BufferedInputStream inputStream = null; + XMLDecoder decoder = null; + try { + inputStream = new BufferedInputStream(new ByteArrayInputStream(encoded.getBytes(XML_CHARSET))); + + decoder = new XMLDecoder(new BufferedInputStream(inputStream, DEFAULT_BUFSIZE), null, null); + + return decoder.readObject(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } finally { + try { + if (decoder != null) { + decoder.close(); + } + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e) { + log.error("XMLDecoder解析XML失败", e.getMessage()); + } + } + + return null; + } + + /** + * 获取当前服务器需要额外校验的License参数 + * + * @return demo.LicenseCheckModel + */ + private LicenseCheckModel getServerInfos() { + //操作系统类型 + String osName = System.getProperty("os.name").toLowerCase(); + AbstractServerInfos abstractServerInfos = null; + + //根据不同操作系统类型选择不同的数据获取方法 + if (osName.startsWith("windows")) { + abstractServerInfos = new WindowsServerInfos(); + } else if (osName.startsWith("linux")) { + abstractServerInfos = new LinuxServerInfos(); + } else {//其他服务器类型 + abstractServerInfos = new LinuxServerInfos(); + } + + return abstractServerInfos.getServerInfos(); + } + + /** + * 校验当前服务器的IP/Mac地址是否在可被允许的IP范围内
+ * 如果存在IP在可被允许的IP/Mac地址范围内,则返回true + * + * @return boolean + */ + private boolean checkIpAddress(List expectedList, List serverList) { + if (expectedList != null && expectedList.size() > 0) { + if (serverList != null && serverList.size() > 0) { + for (String expected : expectedList) { + if (serverList.contains(expected.trim())) { + return true; + } + } + } + + return false; + } else { + return true; + } + } + + /** + * 校验当前服务器硬件(主板、CPU等)序列号是否在可允许范围内 + * + * @return boolean + */ + private boolean checkSerial(String expectedSerial, String serverSerial) { + if (StringUtils.isNotBlank(expectedSerial)) { + if (StringUtils.isNotBlank(serverSerial)) { + if (expectedSerial.equals(serverSerial)) { + return true; + } + } + + return false; + } else { + return true; + } + } + +} diff --git a/src/main/java/org/wfc/common/license/license/LicenseCreator.java b/src/main/java/org/wfc/common/license/license/LicenseCreator.java new file mode 100644 index 0000000..ae87248 --- /dev/null +++ b/src/main/java/org/wfc/common/license/license/LicenseCreator.java @@ -0,0 +1,93 @@ +package org.wfc.common.license.license; + +import org.wfc.common.license.domain.LicenseCreatorParam; +import de.schlichtherle.license.*; +import lombok.extern.slf4j.Slf4j; + +import javax.security.auth.x500.X500Principal; +import java.io.File; +import java.text.MessageFormat; +import java.util.prefs.Preferences; + +/** + * License生成类 + */ +@Slf4j +public class LicenseCreator { + + private final static X500Principal DEFAULT_HOLDER_AND_ISSUER = new X500Principal("CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN"); + private LicenseCreatorParam param; + + public LicenseCreator(LicenseCreatorParam param) { + this.param = param; + } + + /** + * 生成License证书 + * + * @return boolean + */ + public boolean generateLicense() { + try { + LicenseManager licenseManager = new CustomLicenseManager(initLicenseParam()); + LicenseContent licenseContent = initLicenseContent(); + + licenseManager.store(licenseContent, new File(param.getLicensePath())); + + return true; + } catch (Exception e) { + log.error(MessageFormat.format("证书生成失败:{0}", param), e.getMessage(), e); + return false; + } + } + + /** + * 初始化证书生成参数 + * + * @return de.schlichtherle.license.LicenseParam + */ + private LicenseParam initLicenseParam() { + Preferences preferences = Preferences.userNodeForPackage(LicenseCreator.class); + + //设置对证书内容加密的秘钥 + CipherParam cipherParam = new DefaultCipherParam(param.getStorePass()); + + KeyStoreParam privateStoreParam = new CustomKeyStoreParam(LicenseCreator.class + , param.getPrivateKeysStorePath() + , param.getPrivateAlias() + , param.getStorePass() + , param.getKeyPass()); + + LicenseParam licenseParam = new DefaultLicenseParam(param.getSubject() + , preferences + , privateStoreParam + , cipherParam); + + return licenseParam; + } + + /** + * 设置证书生成正文信息 + * + * @return de.schlichtherle.license.LicenseContent + */ + private LicenseContent initLicenseContent() { + LicenseContent licenseContent = new LicenseContent(); + licenseContent.setHolder(DEFAULT_HOLDER_AND_ISSUER); + licenseContent.setIssuer(DEFAULT_HOLDER_AND_ISSUER); + + licenseContent.setSubject(param.getSubject()); + licenseContent.setIssued(param.getIssuedTime()); + licenseContent.setNotBefore(param.getIssuedTime()); + licenseContent.setNotAfter(param.getExpiryTime()); + licenseContent.setConsumerType(param.getConsumerType()); + licenseContent.setConsumerAmount(param.getConsumerAmount()); + licenseContent.setInfo(param.getDescription()); + + //扩展校验服务器硬件信息 + licenseContent.setExtra(param.getLicenseCheckModel()); + + return licenseContent; + } + +} diff --git a/src/main/java/org/wfc/common/license/license/LinuxServerInfos.java b/src/main/java/org/wfc/common/license/license/LinuxServerInfos.java new file mode 100644 index 0000000..e4be54d --- /dev/null +++ b/src/main/java/org/wfc/common/license/license/LinuxServerInfos.java @@ -0,0 +1,86 @@ +package org.wfc.common.license.license; + +import org.apache.commons.lang3.StringUtils; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 用于获取客户Linux服务器的基本信息 + */ +public class LinuxServerInfos extends AbstractServerInfos { + + @Override + protected List getIpAddress() throws Exception { + List result = null; + + //获取所有网络接口 + List inetAddresses = getLocalAllInetAddress(); + + if (inetAddresses != null && inetAddresses.size() > 0) { + result = inetAddresses.stream().map(InetAddress::getHostAddress).distinct().map(String::toLowerCase).collect(Collectors.toList()); + } + + return result; + } + + @Override + protected List getMacAddress() throws Exception { + List result = null; + + //1. 获取所有网络接口 + List inetAddresses = getLocalAllInetAddress(); + + if (inetAddresses != null && inetAddresses.size() > 0) { + //2. 获取所有网络接口的Mac地址 + result = inetAddresses.stream().map(this::getMacByInetAddress).distinct().collect(Collectors.toList()); + } + + return result; + } + + @Override + protected String getCPUSerial() throws Exception { + //序列号 + String serialNumber = ""; + + //使用dmidecode命令获取CPU序列号 + String[] shell = {"/bin/bash", "-c", "dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1"}; + Process process = Runtime.getRuntime().exec(shell); + process.getOutputStream().close(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String line = reader.readLine().trim(); + if (StringUtils.isNotBlank(line)) { + serialNumber = line; + } + + reader.close(); + return serialNumber; + } + + @Override + protected String getMainBoardSerial() throws Exception { + //序列号 + String serialNumber = ""; + + //使用dmidecode命令获取主板序列号 + String[] shell = {"/bin/bash", "-c", "dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1"}; + Process process = Runtime.getRuntime().exec(shell); + process.getOutputStream().close(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String line = reader.readLine().trim(); + if (StringUtils.isNotBlank(line)) { + serialNumber = line; + } + + reader.close(); + return serialNumber; + } +} diff --git a/src/main/java/org/wfc/common/license/license/WindowsServerInfos.java b/src/main/java/org/wfc/common/license/license/WindowsServerInfos.java new file mode 100644 index 0000000..9f6ed5d --- /dev/null +++ b/src/main/java/org/wfc/common/license/license/WindowsServerInfos.java @@ -0,0 +1,144 @@ +package org.wfc.common.license.license; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Collectors; + +/** + * 用于获取客户Windows服务器的基本信息 + */ +public class WindowsServerInfos extends AbstractServerInfos { + + @Override + protected List getIpAddress() throws Exception { + List result = null; + + //获取所有网络接口 + List inetAddresses = getLocalAllInetAddress(); + + if (inetAddresses != null && inetAddresses.size() > 0) { + result = inetAddresses.stream().map(InetAddress::getHostAddress).distinct().map(String::toLowerCase).collect(Collectors.toList()); + } + + return result; + } + + @Override + protected List getMacAddress() throws Exception { + List result = null; + + //1. 获取所有网络接口 + List inetAddresses = getLocalAllInetAddress(); + + if (inetAddresses != null && inetAddresses.size() > 0) { + //2. 获取所有网络接口的Mac地址 + result = inetAddresses.stream().map(this::getMacByInetAddress).distinct().collect(Collectors.toList()); + } + + return result; + } + + private String getCPUSerial2() throws Exception { + //序列号 + String serialNumber = ""; + + //使用WMIC获取CPU序列号 + Process process = Runtime.getRuntime().exec("wmic cpu get processorid"); + process.getOutputStream().close(); + Scanner scanner = new Scanner(process.getInputStream()); + + if (scanner != null && scanner.hasNext()) { + scanner.next(); + } + + if (scanner.hasNext()) { + serialNumber = scanner.next().trim(); + } + + scanner.close(); + return serialNumber; + } + + @Override + protected String getCPUSerial() throws Exception { + String result = ""; + try { + File file = File.createTempFile("tmp", ".vbs"); + file.deleteOnExit(); + FileWriter fw = new FileWriter(file); + String vbs = "Set objWMIService = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\n" + + "Set colItems = objWMIService.ExecQuery _ \n" + " (\"Select * from Win32_Processor\") \n" + + "For Each objItem in colItems \n" + " Wscript.Echo objItem.ProcessorId \n" + + " exit for ' do the first cpu only! \n" + "Next \n"; + + fw.write(vbs); + fw.close(); + Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath()); + BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); + String line; + while ((line = input.readLine()) != null) { + result += line; + } + input.close(); + file.delete(); + } catch (Exception e) { + return getCPUSerial2(); + } + return result.trim(); + } + + private String getMainBoardSerial2() throws Exception { + //序列号 + String serialNumber = ""; + + //使用WMIC获取主板序列号 + Process process = Runtime.getRuntime().exec("wmic baseboard get serialnumber"); + process.getOutputStream().close(); + Scanner scanner = new Scanner(process.getInputStream()); + + if (scanner != null && scanner.hasNext()) { + scanner.next(); + } + + if (scanner.hasNext()) { + serialNumber = scanner.next().trim(); + } + + scanner.close(); + return serialNumber; + } + + @Override + protected String getMainBoardSerial() throws Exception { + + String result = ""; + try { + File file = File.createTempFile("realhowto", ".vbs"); + file.deleteOnExit(); + FileWriter fw = new FileWriter(file); + + String vbs = "Set objWMIService = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\n" + + "Set colItems = objWMIService.ExecQuery _ \n" + " (\"Select * from Win32_BaseBoard\") \n" + + "For Each objItem in colItems \n" + " Wscript.Echo objItem.SerialNumber \n" + + " exit for ' do the first cpu only! \n" + "Next \n"; + + fw.write(vbs); + fw.close(); + Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath()); + BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); + String line; + while ((line = input.readLine()) != null) { + result += line; + } + input.close(); + } catch (Exception e) { + return getMainBoardSerial2(); + } + return result.trim(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..cda4dcb --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,10 @@ +server.port=8081 + +#�������Źػ� +server.shutdown=graceful +#����10�� +spring.lifecycle.timeout-per-shutdown-phase=10s + +#License������� +license.licensePath=/opt/license/license.lic + diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 0000000..c7f7645 --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,23 @@ +${AnsiColor.BRIGHT_YELLOW}Spring Boot: ${spring-boot.formatted-version} +${AnsiColor.BRIGHT_GREEN}$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +${AnsiColor.BRIGHT_YELLOW}$$ _.ooOoo._ $$ +${AnsiColor.BRIGHT_RED}$$ o888888888o $$ +${AnsiColor.BRIGHT_CYAN}$$ 88" . "88 $$ +${AnsiColor.BRIGHT_MAGENTA}$$ (| ^_^ |) $$ +${AnsiColor.BRIGHT_GREEN}$$ O\ = /O $$ +${AnsiColor.BRIGHT_RED}$$ ____/`-----'\____ $$ +${AnsiColor.BRIGHT_CYAN}$$ .' \\| |$$ `. $$ +${AnsiColor.BRIGHT_MAGENTA}$$ / \\||| : |||$$ \ $$ +${AnsiColor.BRIGHT_GREEN}$$ / _||||| -:- |||||- \ $$ +${AnsiColor.BRIGHT_YELLOW}$$ | | \\\ - $$/ | | $$ +${AnsiColor.BRIGHT_GREEN}$$ | \_| ''\-----/'' | | $$ +${AnsiColor.BRIGHT_YELLOW}$$ \ .-\___ `-` ____/-. / $$ +${AnsiColor.BRIGHT_CYAN}$$ ___`. .' /--.--\ `. . ___ $$ +${AnsiColor.BRIGHT_RED}$$ ."" '< `.____\_<|>_/____.' >'"". $$ +${AnsiColor.BRIGHT_GREEN}$$ | | : `- \`.;`.\ _ /``;.`/ - ` : | | $$ +${AnsiColor.BRIGHT_YELLOW}$$ \ \ `-. \_ ___\ /___ _/ .-` / / $$ +${AnsiColor.BRIGHT_CYAN}$$ ========`-.____`-.____\_____/____.-`____.-'======== $$ +${AnsiColor.BRIGHT_MAGENTA}$$ `=---=' $$ +${AnsiColor.BRIGHT_YELLOW}$$ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ $$ +${AnsiColor.BRIGHT_GREEN}$$ 佛祖保佑 永无BUG 永不修改 $$ +${AnsiColor.BRIGHT_YELLOW}$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ \ No newline at end of file diff --git a/src/main/resources/privateKeys.keystore b/src/main/resources/privateKeys.keystore new file mode 100644 index 0000000000000000000000000000000000000000..295a84d0281b92d3872c321591c2321df148cded GIT binary patch literal 1285 zcmezO_TO6u1_mY|W&~rdf}+f_#FEtP)JmYxG!wIlw}EuOK@(%Q0UsNeHX9=gqZX4O zBO@yVOA}+cTKe`HyH=l=DeD4nE6isKGYD(F6>hgONAPTfOrU`m|JH|k>)B>Y2i$G{ zQ~1Arg~Uarq>WoOj%vUgXYoXP@Xa9VEdjIOQbga7;KS7$a(Sq|*{e2s= zIVVq~RaG5Qj9PEX-Qw2Zo1n3>{3&n4rHq&h548UaPyBt*X1nrV`_S1PTb}%CE?z4r zW}tbb+ectW$0x={USp9vehZuK&0lt!sb=!w#2@<>eOtEgl;X9EOd{bW%l6LHnU@(C z74+c2PW`a5Hs)0t2k(EkTY7g>?3?Ev7sO^xpJd^4;=WPsZFYUbn9KJqi)xz{RX2ES zjQ84l%SA^#w&ZJKtxTR#M2nr^>vMK*=SElTT$pK8)XNoBr=7!|f2+syq0LfuljG7` zdK9u1#ZKl$Hm4tUyl)*L`hJGB%(BbgqITT2fsta|e)H8co`R!_HA2tSz>2$C>CpmaCPpSE7M=F5&IY_}oC$3njH%2l%uK8d2FZrp2Apinp)72|OwN8V4u>#P zum_C84(13M2!NDv33KM;Cnx4)a7Z9gXc!#e!=u@%ci`B{E9f4h8C?l6;Sh;WqHM5Aw|pVw(8Ue|j6 zNr_oKz?hg?%UqMd${%}F-wb{1!PVZSAW40rF zXXTXjyMI}|YWf-O!)?pnlpYuv-nZ*Yr2n%*c7eu*EuLb9$}fC0#Duq>=QQd$vFxFZ zSXFmOO|Qm-#p~p>H!mxln76o|`ErxtT#3j_`dnU3YEieUcGW}f4X>O z@a^4RpJ!^W+jDMz$HV2OxopoOBRZqs`kbteXJ<0qRpFv{Z-2UVY}`YBc8S(JkL|Xv zCY`I@wI_(Zr0>$lN_(!lt^->?w3ht{I;rgD&vv-r$)z{Ehr+`bUl6lOwNAWgI$w6h zVnqXa16g3|ljUO(V-b0gZP=+^dGh|JPgkzkg_yosdzkM4TC!#~U@*`H25g(tnSJZL z@BBPAi6`Q_0`t=+k-bluL^38`f700h#^JY%N34GYtCf>b9VwRa)_gMs#G literal 0 HcmV?d00001