Add cryptography
This commit is contained in:
parent
9215ac87b0
commit
49b8fe39a5
@ -1,13 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.example;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.*;
|
||||
import okhttp3.*;
|
||||
import oshi.SystemInfo;
|
||||
import oshi.hardware.CentralProcessor;
|
||||
@ -15,9 +17,18 @@ import oshi.hardware.ComputerSystem;
|
||||
import oshi.hardware.HardwareAbstractionLayer;
|
||||
import oshi.software.os.OperatingSystem;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -32,51 +43,93 @@ import java.util.Map;
|
||||
* @author Braydon
|
||||
* @see <a href="https://git.rainnny.club/Rainnny/LicenseServer">License Server</a>
|
||||
*/
|
||||
public final class LicenseExample {
|
||||
public final class LicenseClient {
|
||||
private static final String ALGORITHM = "RSA"; // The crypto algorithm to use
|
||||
|
||||
/**
|
||||
* The endpoint to use for downloading the {@link PublicKey}.
|
||||
*/
|
||||
private static final String PUBLIC_KEY_ENDPOINT = "/crypto/pub";
|
||||
|
||||
/**
|
||||
* The endpoint to check licenses at.
|
||||
*/
|
||||
private static final String CHECK_ENDPOINT = "http://localhost:7500/check";
|
||||
private static final String CHECK_ENDPOINT = "/check";
|
||||
|
||||
/**
|
||||
* The {@link Gson} instance to use.
|
||||
*/
|
||||
private static final Gson GSON = new GsonBuilder()
|
||||
.serializeNulls()
|
||||
.create();
|
||||
private static final Gson GSON = new GsonBuilder().serializeNulls().create();
|
||||
|
||||
/**
|
||||
* The URL of the license server to make requests to.
|
||||
*/
|
||||
@NonNull private final String appUrl;
|
||||
|
||||
/**
|
||||
* The product to use for client.
|
||||
*/
|
||||
@NonNull private final String product;
|
||||
|
||||
/**
|
||||
* The {@link OkHttpClient} to use for requests.
|
||||
*/
|
||||
@NonNull private final OkHttpClient httpClient;
|
||||
|
||||
/**
|
||||
* The {@link PublicKey} to use for encryption.
|
||||
*/
|
||||
@NonNull private final PublicKey publicKey;
|
||||
|
||||
public LicenseClient(@NonNull String appUrl, @NonNull String product, @NonNull File publicKeyFile) {
|
||||
this.appUrl = appUrl;
|
||||
this.product = product;
|
||||
httpClient = new OkHttpClient(); // Create a new http client
|
||||
publicKey = fetchPublicKey(publicKeyFile); // Fetch our public key
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the public key from the given bytes.
|
||||
*
|
||||
* @param bytes the bytes of the public key
|
||||
* @return the public key
|
||||
* @see PrivateKey for public key
|
||||
*/
|
||||
@SneakyThrows
|
||||
private static PublicKey readPublicKey(byte[] bytes) {
|
||||
return KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the license with the given
|
||||
* key for the given product.
|
||||
*
|
||||
* @param key the key to check
|
||||
* @param product the product the key belongs to
|
||||
* @return the license response
|
||||
* @see LicenseResponse for response
|
||||
*/
|
||||
@NonNull
|
||||
public static LicenseResponse check(@NonNull String key, @NonNull String product) {
|
||||
public LicenseResponse check(@NonNull String key) {
|
||||
String hardwareId = getHardwareId(); // Get the hardware id of the machine
|
||||
|
||||
// Build the json body
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("key", key);
|
||||
body.put("key", encrypt(key));
|
||||
body.put("product", product);
|
||||
body.put("hwid", hardwareId);
|
||||
body.put("hwid", encrypt(hardwareId));
|
||||
String bodyJson = GSON.toJson(body); // The json body
|
||||
|
||||
OkHttpClient client = new OkHttpClient(); // Create a new http client
|
||||
MediaType mediaType = MediaType.parse("application/json"); // Ensure the media type is json
|
||||
RequestBody requestBody = RequestBody.create(bodyJson, mediaType); // Build the request body
|
||||
RequestBody requestBody = RequestBody.create(mediaType, bodyJson); // Build the request body
|
||||
Request request = new Request.Builder()
|
||||
.url(CHECK_ENDPOINT)
|
||||
.url(appUrl + CHECK_ENDPOINT)
|
||||
.post(requestBody)
|
||||
.build(); // Build the POST request
|
||||
|
||||
Response response = null; // The response of the request
|
||||
int responseCode = -1; // The response code of the request
|
||||
try { // Attempt to execute the request
|
||||
response = client.newCall(request).execute();
|
||||
response = httpClient.newCall(request).execute();
|
||||
responseCode = response.code();
|
||||
|
||||
// If the response is successful, we can parse the response
|
||||
@ -127,6 +180,43 @@ public final class LicenseExample {
|
||||
return new LicenseResponse(responseCode, "An unknown error occurred");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the public key.
|
||||
* <p>
|
||||
* If the public key is not already present, we
|
||||
* fetch it from the server. Otherwise, the public
|
||||
* key is loaded from the file.
|
||||
* </p>
|
||||
*
|
||||
* @param publicKeyFile the public key file
|
||||
* @return the public key
|
||||
* @see PublicKey for public key
|
||||
*/
|
||||
@SneakyThrows
|
||||
private PublicKey fetchPublicKey(@NonNull File publicKeyFile) {
|
||||
byte[] publicKey;
|
||||
if (publicKeyFile.exists()) { // Public key exists, use it
|
||||
publicKey = Files.readAllBytes(publicKeyFile.toPath());
|
||||
} else {
|
||||
Request request = new Request.Builder()
|
||||
.url(appUrl + PUBLIC_KEY_ENDPOINT)
|
||||
.build(); // Build the GET request
|
||||
@Cleanup Response response = httpClient.newCall(request).execute(); // Make the request
|
||||
if (!response.isSuccessful()) { // Response wasn't successful
|
||||
throw new IOException("Failed to download the public key, got response " + response.code());
|
||||
}
|
||||
ResponseBody body = response.body(); // Get the response body
|
||||
assert body != null; // We need a response body
|
||||
publicKey = body.bytes(); // Read our public key
|
||||
|
||||
// Write the response to the public key file
|
||||
try (FileOutputStream outputStream = new FileOutputStream(publicKeyFile)) {
|
||||
outputStream.write(publicKey);
|
||||
}
|
||||
}
|
||||
return readPublicKey(publicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique hardware
|
||||
* identifier of this machine.
|
||||
@ -134,7 +224,7 @@ public final class LicenseExample {
|
||||
* @return the hardware id
|
||||
*/
|
||||
@NonNull
|
||||
private static String getHardwareId() {
|
||||
private String getHardwareId() {
|
||||
SystemInfo systemInfo = new SystemInfo();
|
||||
OperatingSystem operatingSystem = systemInfo.getOperatingSystem();
|
||||
HardwareAbstractionLayer hardwareAbstractionLayer = systemInfo.getHardware();
|
||||
@ -155,9 +245,25 @@ public final class LicenseExample {
|
||||
+ String.format("%08x", processorIdentifier.hashCode()) + "-" + processors;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
/**
|
||||
* Encrypt the given input.
|
||||
*
|
||||
* @param input the encrypted input
|
||||
* @return the encrypted result
|
||||
*/
|
||||
@SneakyThrows @NonNull
|
||||
private String encrypt(@NonNull String input) {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM); // Create our cipher
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey); // Set our mode and public key
|
||||
return Base64.getEncoder().encodeToString(cipher.doFinal(input.getBytes())); // Return our encrypted result
|
||||
}
|
||||
|
||||
/**
|
||||
* The response of a license check.
|
||||
*
|
||||
* @see #check(String)
|
||||
*/
|
||||
@AllArgsConstructor @Getter @ToString
|
||||
public static class LicenseResponse {
|
||||
/**
|
||||
* The status code of the response.
|
@ -1,11 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.example;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Braydon
|
||||
*/
|
||||
public final class Main {
|
||||
public static void main(String[] args) {
|
||||
LicenseExample.LicenseResponse response = LicenseExample.check("XXXX-XXXX-XXXX-XXXX", "Example");
|
||||
LicenseClient client = new LicenseClient("http://localhost:7500", "Example", new File("public.key")); // Create the client
|
||||
LicenseClient.LicenseResponse response = client.check("XXXX-XXXX-XXXX-XXXX"); // Check our license
|
||||
if (!response.isValid()) { // License isn't valid
|
||||
System.err.println("Invalid license: " + response.getError());
|
||||
return;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.common;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.security.*;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* @author Braydon
|
||||
*/
|
||||
@UtilityClass
|
||||
public final class CryptographyUtils {
|
||||
private static final String ALGORITHM = "RSA"; // The algorithm to use
|
||||
|
||||
/**
|
||||
* Generate a new key pair.
|
||||
*
|
||||
* @return the key pair
|
||||
* @see KeyPair for key pair
|
||||
*/
|
||||
@NonNull @SneakyThrows
|
||||
public static KeyPair generateKeyPair() {
|
||||
KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM); // Create a generator
|
||||
generator.initialize(2048); // Set the key size
|
||||
return generator.generateKeyPair(); // Return our generated key pair
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the public key from the given file.
|
||||
*
|
||||
* @param keyFile the key file to read
|
||||
* @return the public key
|
||||
* @see PrivateKey for public key
|
||||
*/
|
||||
@SneakyThrows
|
||||
public static PublicKey readPublicKey(@NonNull File keyFile) {
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Files.readAllBytes(keyFile.toPath())); // Get the key spec
|
||||
return KeyFactory.getInstance(ALGORITHM).generatePublic(keySpec); // Return the public key from the key spec
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the private key from the given file.
|
||||
*
|
||||
* @param keyFile the key file to read
|
||||
* @return the private key
|
||||
* @see PrivateKey for private key
|
||||
*/
|
||||
@SneakyThrows
|
||||
public static PrivateKey readPrivateKey(@NonNull File keyFile) {
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Files.readAllBytes(keyFile.toPath())); // Get the key spec
|
||||
return KeyFactory.getInstance(ALGORITHM).generatePrivate(keySpec); // Return the private key from the key spec
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the given input with
|
||||
* the provided private key.
|
||||
*
|
||||
* @param input the encrypted input
|
||||
* @param privateKey the private key
|
||||
* @return the decrypted result
|
||||
* @see PrivateKey for private key
|
||||
*/
|
||||
@SneakyThrows @NonNull
|
||||
public static String decryptMessage(@NonNull String input, @NonNull PrivateKey privateKey) {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM); // Create the cipher
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey); // Set our mode and private key
|
||||
return new String(cipher.doFinal(Base64.getDecoder().decode(input))); // Return our decrypted result
|
||||
}
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.common;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.common;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.common;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.common;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.controller;
|
||||
|
||||
import lombok.NonNull;
|
||||
import me.braydon.license.model.License;
|
||||
import me.braydon.license.service.CryptographyService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* @author Braydon
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/crypto", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public final class CryptographyController {
|
||||
/**
|
||||
* The {@link CryptographyService} to use.
|
||||
*/
|
||||
@NonNull private final CryptographyService service;
|
||||
|
||||
@Autowired
|
||||
public CryptographyController(@NonNull CryptographyService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the public key file.
|
||||
*
|
||||
* @return the response entity
|
||||
* @see PublicKey for public key
|
||||
* @see License for license
|
||||
* @see ResponseEntity for response entity
|
||||
*/
|
||||
@GetMapping("/pub")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Resource> publicKey() {
|
||||
byte[] publicKey = service.getKeyPair().getPublic().getEncoded(); // Get the public key
|
||||
String fileName = "public.key"; // The name of the file to download
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
|
||||
.contentLength(publicKey.length)
|
||||
.body(new ByteArrayResource(publicKey));
|
||||
}
|
||||
}
|
@ -1,12 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.NonNull;
|
||||
import me.braydon.license.common.CryptographyUtils;
|
||||
import me.braydon.license.common.IPUtils;
|
||||
import me.braydon.license.dto.LicenseCheckBodyDTO;
|
||||
import me.braydon.license.dto.LicenseDTO;
|
||||
import me.braydon.license.exception.APIException;
|
||||
import me.braydon.license.model.License;
|
||||
import me.braydon.license.service.CryptographyService;
|
||||
import me.braydon.license.service.LicenseService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@ -14,6 +21,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -22,14 +30,20 @@ import java.util.Map;
|
||||
@RestController
|
||||
@RequestMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public final class LicenseController {
|
||||
/**
|
||||
* The {@link CryptographyService} to use.
|
||||
*/
|
||||
@NonNull private final CryptographyService cryptographyService;
|
||||
|
||||
/**
|
||||
* The {@link LicenseService} to use.
|
||||
*/
|
||||
@NonNull private final LicenseService service;
|
||||
@NonNull private final LicenseService licenseService;
|
||||
|
||||
@Autowired
|
||||
public LicenseController(@NonNull LicenseService service) {
|
||||
this.service = service;
|
||||
public LicenseController(@NonNull CryptographyService cryptographyService, @NonNull LicenseService licenseService) {
|
||||
this.cryptographyService = cryptographyService;
|
||||
this.licenseService = licenseService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,24 +67,34 @@ public final class LicenseController {
|
||||
if (IPUtils.getIpType(ip) == -1) {
|
||||
throw new APIException(HttpStatus.BAD_REQUEST, "Invalid IP address");
|
||||
}
|
||||
// Ensure the HWID is valid
|
||||
String hwidString = body.getHwid();
|
||||
String key;
|
||||
String hwid;
|
||||
try {
|
||||
PrivateKey privateKey = cryptographyService.getKeyPair().getPrivate(); // Get our private key
|
||||
key = CryptographyUtils.decryptMessage(body.getKey(), privateKey); // Decrypt our license key
|
||||
hwid = CryptographyUtils.decryptMessage(body.getHwid(), privateKey); // Decrypt our hwid
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new APIException(HttpStatus.BAD_REQUEST, "Signature Error");
|
||||
}
|
||||
|
||||
// Validating that the UUID is in the correct format
|
||||
boolean invalidHwid = true;
|
||||
if (hwidString.contains("-")) {
|
||||
int segments = hwidString.substring(0, hwidString.lastIndexOf("-")).split("-").length;
|
||||
if (hwid.contains("-")) {
|
||||
int segments = hwid.substring(0, hwid.lastIndexOf("-")).split("-").length;
|
||||
if (segments == 4) {
|
||||
invalidHwid = false;
|
||||
}
|
||||
}
|
||||
if (invalidHwid) {
|
||||
if (invalidHwid) { // Invalid HWID
|
||||
throw new APIException(HttpStatus.BAD_REQUEST, "Invalid HWID");
|
||||
}
|
||||
|
||||
// Check the license
|
||||
License license = service.check(
|
||||
body.getKey(),
|
||||
License license = licenseService.check(
|
||||
key,
|
||||
body.getProduct(),
|
||||
ip,
|
||||
hwidString
|
||||
hwid
|
||||
);
|
||||
// Return OK with the license DTO
|
||||
return ResponseEntity.ok(new LicenseDTO(
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.exception;
|
||||
|
||||
import me.braydon.license.model.License;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.exception;
|
||||
|
||||
import me.braydon.license.model.License;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.exception;
|
||||
|
||||
import me.braydon.license.model.License;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.exception;
|
||||
|
||||
import me.braydon.license.model.License;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.model;
|
||||
|
||||
import lombok.Getter;
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.repository;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.service;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.braydon.license.common.CryptographyUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyPair;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* @author Braydon
|
||||
*/
|
||||
@Service
|
||||
@Slf4j(topic = "Cryptography")
|
||||
@Getter
|
||||
public final class CryptographyService {
|
||||
/**
|
||||
* Our {@link KeyPair}.
|
||||
*/
|
||||
@NonNull private final KeyPair keyPair;
|
||||
|
||||
@SneakyThrows
|
||||
public CryptographyService() {
|
||||
File publicKeyFile = new File("public.key"); // The private key
|
||||
File privateKeyFile = new File("private.key"); // The private key
|
||||
if (!publicKeyFile.exists() || !privateKeyFile.exists()) { // Missing private key, generate new key pair.
|
||||
keyPair = CryptographyUtils.generateKeyPair(); // Generate new key pair
|
||||
writeKey(keyPair.getPublic().getEncoded(), publicKeyFile); // Write our public key
|
||||
writeKey(keyPair.getPrivate().getEncoded(), privateKeyFile); // Write our private key
|
||||
log.info("New key pair has been generated");
|
||||
log.info(Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
|
||||
return;
|
||||
}
|
||||
// Load our private key from the file
|
||||
keyPair = new KeyPair(CryptographyUtils.readPublicKey(publicKeyFile), CryptographyUtils.readPrivateKey(privateKeyFile));
|
||||
log.info("Loaded private key from file " + privateKeyFile.getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given contents to the provided file.
|
||||
*
|
||||
* @param contents the content bytes to write
|
||||
* @param file the file to write to
|
||||
*/
|
||||
private void writeKey(byte[] contents, @NonNull File file) {
|
||||
try (FileOutputStream outputStream = new FileOutputStream(file)) {
|
||||
outputStream.write(contents);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.service;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
@ -33,7 +38,6 @@ import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||
import org.mindrot.jbcrypt.BCrypt;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.info.BuildProperties;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.awt.*;
|
||||
@ -59,7 +63,7 @@ public final class DiscordService {
|
||||
/**
|
||||
* The version of this Springboot application.
|
||||
*/
|
||||
@NonNull private final String applicationVersion;
|
||||
@NonNull private String applicationVersion = "n/a";
|
||||
|
||||
/**
|
||||
* The salt to use for hashing license keys.
|
||||
@ -140,9 +144,9 @@ public final class DiscordService {
|
||||
.build();
|
||||
|
||||
@Autowired
|
||||
public DiscordService(@NonNull LicenseRepository licenseRepository, @NonNull BuildProperties buildProperties) {
|
||||
public DiscordService(@NonNull LicenseRepository licenseRepository/*, @NonNull BuildProperties buildProperties*/) {
|
||||
this.licenseRepository = licenseRepository;
|
||||
this.applicationVersion = buildProperties.getVersion();
|
||||
// this.applicationVersion = buildProperties.getVersion();
|
||||
}
|
||||
|
||||
@PostConstruct @SneakyThrows
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||
*
|
||||
* For inquiries, please contact braydonrainnny@gmail.com
|
||||
*/
|
||||
package me.braydon.license.service;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
Loading…
x
Reference in New Issue
Block a user