feat: 支持激活码license
This commit is contained in:
@@ -70,4 +70,29 @@ public class LicenseCheckModel implements Serializable {
|
|||||||
", mainBoardSerial='" + mainBoardSerial + '\'' +
|
", mainBoardSerial='" + mainBoardSerial + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toJsonString() {
|
||||||
|
StringBuilder jsonBuilder = new StringBuilder();
|
||||||
|
jsonBuilder.append("{");
|
||||||
|
// jsonBuilder.append("\"ipAddress\": [");
|
||||||
|
// for (String ip : ipAddress) {
|
||||||
|
// jsonBuilder.append("\"").append(ip).append("\", ");
|
||||||
|
// }
|
||||||
|
// jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
|
||||||
|
// jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
|
||||||
|
// jsonBuilder.append("], ");
|
||||||
|
// jsonBuilder.append("\"macAddress\": [");
|
||||||
|
// for (String mac : macAddress) {
|
||||||
|
// jsonBuilder.append("\"").append(mac).append("\", ");
|
||||||
|
// }
|
||||||
|
// jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
|
||||||
|
// jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
|
||||||
|
// jsonBuilder.append("], ");
|
||||||
|
jsonBuilder.append("\"cpuSerial\": \"").append(cpuSerial).append("\", ");
|
||||||
|
jsonBuilder.append("\"mainBoardSerial\": \"").append(mainBoardSerial).append("\"");
|
||||||
|
// jsonBuilder.append("\"registerAmount\": \"").append(registerAmount).append("\"");
|
||||||
|
jsonBuilder.append("}");
|
||||||
|
|
||||||
|
return jsonBuilder.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.wfc.common.license.runner;
|
package org.wfc.common.license.runner;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -8,13 +9,19 @@ import org.springframework.boot.ApplicationArguments;
|
|||||||
import org.springframework.boot.ApplicationRunner;
|
import org.springframework.boot.ApplicationRunner;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.wfc.common.license.LicenseVerify;
|
import org.wfc.common.license.LicenseVerify;
|
||||||
|
import org.wfc.common.license.domain.LicenseCheckModel;
|
||||||
import org.wfc.common.license.domain.LicenseVerifyParam;
|
import org.wfc.common.license.domain.LicenseVerifyParam;
|
||||||
|
import org.wfc.common.license.serverinfo.AbstractServerInfos;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
@@ -31,6 +38,8 @@ public class LicenseCheckRunner implements ApplicationRunner {
|
|||||||
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||||
private ScheduledFuture<?> scheduledFuture;
|
private ScheduledFuture<?> scheduledFuture;
|
||||||
|
|
||||||
|
private static final String key = "wfcwanfiAdmin6666";
|
||||||
|
|
||||||
|
|
||||||
// 启动定时任务
|
// 启动定时任务
|
||||||
public void startTimer() {
|
public void startTimer() {
|
||||||
@@ -114,6 +123,73 @@ public class LicenseCheckRunner implements ApplicationRunner {
|
|||||||
log.info("++++++++ 证书安装结束 ++++++++");
|
log.info("++++++++ 证书安装结束 ++++++++");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generate() {
|
||||||
|
try {
|
||||||
|
LicenseCheckModel serverInfos = AbstractServerInfos.getServer("").getServerInfos();
|
||||||
|
|
||||||
|
//对象序列化为json
|
||||||
|
String jsonString = serverInfos.toJsonString();
|
||||||
|
System.out.println("原始数据 = " + jsonString);
|
||||||
|
//加密
|
||||||
|
String encryptedJson = encrypt(jsonString);
|
||||||
|
System.out.println("加密后 = " + encryptedJson);
|
||||||
|
// 解密
|
||||||
|
String decryptedJson = decrypt(encryptedJson);
|
||||||
|
System.out.println("解密后 = " + decryptedJson);
|
||||||
|
// 比较解密后的字符串与原始字符串
|
||||||
|
if (jsonString.equals(decryptedJson)) {
|
||||||
|
} else {
|
||||||
|
log.info("解密后的字符串与原始字符串不同");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 断言
|
||||||
|
assert jsonString.equals(decryptedJson) : "解密后的字符串与原始字符串不匹配";
|
||||||
|
|
||||||
|
// 反序列化为对象
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
LicenseCheckModel licenseParam = null;
|
||||||
|
licenseParam = mapper.readValue(decryptedJson, LicenseCheckModel.class);
|
||||||
|
// 标记为null的字段需要特殊处理
|
||||||
|
// if ("null".equals(licenseParam.getRegisterAmount())) {
|
||||||
|
// licenseParam.setRegisterAmount(null);
|
||||||
|
// }
|
||||||
|
FileWriter writer = new FileWriter(licenseProperties.getCodePath());
|
||||||
|
writer.write(encryptedJson);
|
||||||
|
writer.close();
|
||||||
|
log.info("licenseParam {}", licenseParam);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("生成激活码失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String encrypt(String json) throws Exception {
|
||||||
|
byte[] keyBytes = key.getBytes();
|
||||||
|
MessageDigest sha = MessageDigest.getInstance("SHA-256");
|
||||||
|
keyBytes = sha.digest(keyBytes);
|
||||||
|
keyBytes = java.util.Arrays.copyOf(keyBytes, 16);
|
||||||
|
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
|
||||||
|
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||||
|
byte[] encryptedBytes = cipher.doFinal(json.getBytes());
|
||||||
|
return Base64.getEncoder().encodeToString(encryptedBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String decrypt(String encryptedJson) throws Exception {
|
||||||
|
byte[] keyBytes = key.getBytes();
|
||||||
|
MessageDigest sha = MessageDigest.getInstance("SHA-256");
|
||||||
|
keyBytes = sha.digest(keyBytes);
|
||||||
|
keyBytes = java.util.Arrays.copyOf(keyBytes, 16);
|
||||||
|
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
|
||||||
|
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||||
|
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedJson);
|
||||||
|
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
|
||||||
|
return new String(decryptedBytes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>获取文件的md5</p>
|
* <p>获取文件的md5</p>
|
||||||
*/
|
*/
|
||||||
@@ -159,6 +235,7 @@ public class LicenseCheckRunner implements ApplicationRunner {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
|
generate();
|
||||||
install();
|
install();
|
||||||
startTimer();
|
startTimer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ public class LicenseProperties {
|
|||||||
*/
|
*/
|
||||||
private String licensePath = "/opt/wfc/license/license.lic";
|
private String licensePath = "/opt/wfc/license/license.lic";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 激活码生成路径
|
||||||
|
*/
|
||||||
|
private String codePath = "/opt/wfc/license/activation_code.txt";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 密钥库存储路径
|
* 密钥库存储路径
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,17 +20,18 @@ public abstract class AbstractServerInfos {
|
|||||||
* 组装需要额外校验的License参数
|
* 组装需要额外校验的License参数
|
||||||
*
|
*
|
||||||
* @return demo.LicenseCheckModel
|
* @return demo.LicenseCheckModel
|
||||||
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public LicenseCheckModel getServerInfos() {
|
public LicenseCheckModel getServerInfos() {
|
||||||
LicenseCheckModel result = new LicenseCheckModel();
|
LicenseCheckModel result = new LicenseCheckModel();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result.setIpAddress(this.getIpAddress());
|
// result.setIpAddress(this.getIpAddress());
|
||||||
result.setMacAddress(this.getMacAddress());
|
// result.setMacAddress(this.getMacAddress());
|
||||||
result.setCpuSerial(this.getCPUSerial());
|
result.setCpuSerial(this.getCPUSerial());
|
||||||
result.setMainBoardSerial(this.getMainBoardSerial());
|
result.setMainBoardSerial(this.getMainBoardSerial());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("获取服务器硬件信息失败 {}", e.getMessage());
|
log.error("获取服务器硬件信息失败", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -86,7 +87,6 @@ public abstract class AbstractServerInfos {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,12 +100,10 @@ public abstract class AbstractServerInfos {
|
|||||||
try {
|
try {
|
||||||
byte[] mac = NetworkInterface.getByInetAddress(inetAddr).getHardwareAddress();
|
byte[] mac = NetworkInterface.getByInetAddress(inetAddr).getHardwareAddress();
|
||||||
StringBuffer stringBuffer = new StringBuffer();
|
StringBuffer stringBuffer = new StringBuffer();
|
||||||
|
|
||||||
for (int i = 0; i < mac.length; i++) {
|
for (int i = 0; i < mac.length; i++) {
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
stringBuffer.append("-");
|
stringBuffer.append("-");
|
||||||
}
|
}
|
||||||
|
|
||||||
//将十六进制byte转化为字符串
|
//将十六进制byte转化为字符串
|
||||||
String temp = Integer.toHexString(mac[i] & 0xff);
|
String temp = Integer.toHexString(mac[i] & 0xff);
|
||||||
if (temp.length() == 1) {
|
if (temp.length() == 1) {
|
||||||
@@ -114,14 +112,33 @@ public abstract class AbstractServerInfos {
|
|||||||
stringBuffer.append(temp);
|
stringBuffer.append(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stringBuffer.toString().toUpperCase();
|
return stringBuffer.toString().toUpperCase();
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
log.error("获取某个网络接口的Mac地址异常", e.getMessage());
|
log.error("获取某个网络接口的Mac地址异常", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>获取服务器信息</p>
|
||||||
|
*
|
||||||
|
* @param osName 系统类型
|
||||||
|
* @return AGxServerInfos 服务信息
|
||||||
|
*/
|
||||||
|
public static AbstractServerInfos getServer(String osName) {
|
||||||
|
if ("".equals(osName) || osName == null) {
|
||||||
|
osName = System.getProperty("os.name").toLowerCase();
|
||||||
|
}
|
||||||
|
AbstractServerInfos abstractServerInfos;
|
||||||
|
// 根据不同操作系统类型选择不同的数据获取方法
|
||||||
|
if (osName.startsWith("windows")) {
|
||||||
|
abstractServerInfos = new WindowsServerInfos();
|
||||||
|
} else if (osName.startsWith("linux")) {
|
||||||
|
abstractServerInfos = new LinuxServerInfos();
|
||||||
|
} else {// 其他服务器类型
|
||||||
|
abstractServerInfos = new LinuxServerInfos();
|
||||||
|
}
|
||||||
|
return abstractServerInfos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package org.wfc.common.license.serverinfo;
|
package org.wfc.common.license.serverinfo;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -12,9 +13,6 @@ import java.util.stream.Collectors;
|
|||||||
*/
|
*/
|
||||||
public class LinuxServerInfos extends AbstractServerInfos {
|
public class LinuxServerInfos extends AbstractServerInfos {
|
||||||
|
|
||||||
private final String[] CPU_SHELL = {"/bin/bash", "-c", "dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1"};
|
|
||||||
private final String[] MAIN_BOARD_SHELL = {"/bin/bash", "-c", "dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1"};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<String> getIpAddress() throws Exception {
|
protected List<String> getIpAddress() throws Exception {
|
||||||
List<String> result = null;
|
List<String> result = null;
|
||||||
@@ -46,50 +44,43 @@ public class LinuxServerInfos extends AbstractServerInfos {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getCPUSerial() throws Exception {
|
protected String getCPUSerial() throws Exception {
|
||||||
String result = "";
|
//序列号
|
||||||
String CPU_ID_CMD = "dmidecode";
|
String serialNumber = "";
|
||||||
BufferedReader bufferedReader = null;
|
|
||||||
Process p = null;
|
//使用dmidecode命令获取CPU序列号
|
||||||
try {
|
String[] shell = {"/bin/bash", "-c", "dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1"};
|
||||||
p = Runtime.getRuntime().exec(new String[]{"sh", "-c", CPU_ID_CMD});// 管道
|
Process process = Runtime.getRuntime().exec(shell);
|
||||||
bufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
process.getOutputStream().close();
|
||||||
String line = null;
|
|
||||||
int index = -1;
|
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
while ((line = bufferedReader.readLine()) != null) {
|
|
||||||
// 寻找标示字符串[hwaddr]
|
String line = reader.readLine().trim();
|
||||||
index = line.toLowerCase().indexOf("uuid");
|
if (StringUtils.isNotBlank(line)) {
|
||||||
if (index >= 0) {// 找到了
|
serialNumber = line;
|
||||||
// 取出mac地址并去除2边空格
|
|
||||||
result = line.substring(index + "uuid".length() + 1).trim();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("获取cpu硬件信息失败 " + e);
|
|
||||||
}
|
}
|
||||||
return result.trim();
|
|
||||||
// return GxServerSerialHelper.getLinuxSerial(CPU_SHELL);
|
reader.close();
|
||||||
|
return serialNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getMainBoardSerial() throws Exception {
|
protected String getMainBoardSerial() throws Exception {
|
||||||
String result = "";
|
//序列号
|
||||||
String maniBord_cmd = "dmidecode | grep 'Serial Number' | awk '{print $3}' | tail -1";
|
String serialNumber = "";
|
||||||
Process p;
|
|
||||||
try {
|
|
||||||
p = Runtime.getRuntime().exec(new String[]{"sh", "-c", maniBord_cmd});// 管道
|
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
|
||||||
String line;
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
result += line;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
br.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("获取主板信息错误" + e);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
// return GxServerSerialHelper.getLinuxSerial(MAIN_BOARD_SHELL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//使用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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user