From 8d97e0efa42c8235c38ad1b1c950d4386f5a0672 Mon Sep 17 00:00:00 2001 From: Braydon Date: Sat, 2 Dec 2023 04:08:12 -0500 Subject: [PATCH] Example -> Example-Java --- Example/pom.xml | 79 ---- .../me/braydon/example/LicenseClient.java | 337 ------------------ .../main/java/me/braydon/example/Main.java | 35 -- 3 files changed, 451 deletions(-) delete mode 100644 Example/pom.xml delete mode 100644 Example/src/main/java/me/braydon/example/LicenseClient.java delete mode 100644 Example/src/main/java/me/braydon/example/Main.java diff --git a/Example/pom.xml b/Example/pom.xml deleted file mode 100644 index ed27a0f..0000000 --- a/Example/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - 4.0.0 - - me.braydon - Example - 1.0.0 - - - 17 - ${java.version} - ${java.version} - UTF-8 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - ${java.version} - ${java.version} - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.1.0 - - - package - - shade - - - - - - - - - - - org.projectlombok - lombok - 1.18.28 - provided - - - - - com.google.code.gson - gson - 2.10.1 - compile - - - - - com.github.oshi - oshi-core - 6.4.2 - compile - - - - - com.squareup.okhttp3 - okhttp - 4.11.0 - compile - - - \ No newline at end of file diff --git a/Example/src/main/java/me/braydon/example/LicenseClient.java b/Example/src/main/java/me/braydon/example/LicenseClient.java deleted file mode 100644 index 3849023..0000000 --- a/Example/src/main/java/me/braydon/example/LicenseClient.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * 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.*; -import okhttp3.*; -import oshi.SystemInfo; -import oshi.hardware.CentralProcessor; -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; - -/** - * An example of how to interact - * with the license server. This - * can be conveniently used in - * any project by simply copying - * the class into your project. - * - * @author Braydon - * @see License Server - */ -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 = "/check"; - - /** - * The {@link Gson} instance to use. - */ - 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 - * @return the license response - * @see LicenseResponse for response - */ - @NonNull - public LicenseResponse check(@NonNull String key) { - String hardwareId = getHardwareId(); // Get the hardware id of the machine - - // Build the json body - Map body = new HashMap<>(); - body.put("key", encrypt(key)); - body.put("product", product); - body.put("hwid", encrypt(hardwareId)); - String bodyJson = GSON.toJson(body); // The json body - - MediaType mediaType = MediaType.parse("application/json"); // Ensure the media type is json - RequestBody requestBody = RequestBody.create(mediaType, bodyJson); // Build the request body - Request request = new Request.Builder() - .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 = httpClient.newCall(request).execute(); - responseCode = response.code(); - - // If the response is successful, we can parse the response - if (response.isSuccessful()) { - ResponseBody responseBody = response.body(); - assert responseBody != null; // We don't want the response body being null - - JsonObject json = GSON.fromJson(responseBody.string(), JsonObject.class); // Parse the json - JsonElement description = json.get("description"); - JsonElement ownerSnowflake = json.get("ownerSnowflake"); - JsonElement ownerName = json.get("ownerName"); - JsonElement plan = json.get("plan"); - JsonElement latestVersion = json.get("latestVersion"); - - // Parsing the expiration date if we have one - JsonElement expires = json.get("expires"); - Date expiresDate = null; - if (!expires.isJsonNull()) { - OffsetDateTime offsetDateTime = OffsetDateTime.parse(expires.getAsString(), DateTimeFormatter.ISO_OFFSET_DATE_TIME); - expiresDate = Date.from(offsetDateTime.toInstant()); - } - - // Return the license response - return new LicenseResponse(200, null, - description.isJsonNull() ? null : description.getAsString(), - ownerSnowflake.isJsonNull() ? -1 : ownerSnowflake.getAsLong(), - ownerName.isJsonNull() ? null : ownerName.getAsString(), - plan.getAsString(), - latestVersion.getAsString(), - expires.isJsonNull() ? null : expiresDate - ); - } else { - ResponseBody errorBody = response.body(); // Get the error body - if (errorBody != null) { // If we have an error body, we can parse it - String errorResponse = errorBody.string(); - JsonObject jsonError = GSON.fromJson(errorResponse, JsonObject.class); - JsonElement errorMessage = jsonError.get("error"); - if (!errorMessage.isJsonNull()) { // We have an error message, return it - return new LicenseResponse(responseCode, errorMessage.getAsString()); - } - } - } - } catch (IOException ex) { - ex.printStackTrace(); - } finally { - // Close the response if it's open - if (response != null) { - response.close(); - } - } - // Return an unknown error - return new LicenseResponse(responseCode, "An unknown error occurred"); - } - - /** - * Fetch the public key. - *

- * If the public key is not already present, we - * fetch it from the server. Otherwise, the public - * key is loaded from the file. - *

- * - * @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. - * - * @return the hardware id - */ - @NonNull - private String getHardwareId() { - SystemInfo systemInfo = new SystemInfo(); - OperatingSystem operatingSystem = systemInfo.getOperatingSystem(); - HardwareAbstractionLayer hardwareAbstractionLayer = systemInfo.getHardware(); - CentralProcessor centralProcessor = hardwareAbstractionLayer.getProcessor(); - ComputerSystem computerSystem = hardwareAbstractionLayer.getComputerSystem(); - - // Retrieve necessary hardware information - String vendor = operatingSystem.getManufacturer(); - String processorSerialNumber = computerSystem.getSerialNumber(); - String uuid = computerSystem.getHardwareUUID(); - String processorIdentifier = centralProcessor.getProcessorIdentifier().getIdentifier(); - int processors = centralProcessor.getLogicalProcessorCount(); - - // Generate a unique hardware id using the retrieved information - return String.format("%08x", vendor.hashCode()) + "-" - + String.format("%08x", processorSerialNumber.hashCode()) + "-" - + String.format("%08x", uuid.hashCode()) + "-" - + String.format("%08x", processorIdentifier.hashCode()) + "-" + processors; - } - - /** - * 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. - */ - private final long status; - - /** - * The error in the response, null if none. - */ - private String error; - - /** - * The description of the license, present if valid. - */ - private String description; - - /** - * The Discord snowflake of the license owner, present - * if valid and there is an owner. - */ - private long ownerSnowflake; - - /** - * The Discord name of the license owner, present - * if valid and there is an owner. - */ - private String ownerName; - - /** - * The plan for this license. - */ - @NonNull private String plan; - - /** - * The latest version of the product this license is for. - */ - @NonNull private String latestVersion; - - /** - * The optional expiration {@link Date} of the license. - */ - private Date expires; - - public LicenseResponse(long status, @NonNull String error) { - this.status = status; - this.error = error; - } - - /** - * Check if the license is valid. - * - * @return true if valid, otherwise false - */ - public boolean isValid() { - return status == 200; - } - - /** - * Check if the license is permanent. - * - * @return true if permanent, otherwise false - */ - public boolean isPermanent() { - return expires == null; - } - } -} \ No newline at end of file diff --git a/Example/src/main/java/me/braydon/example/Main.java b/Example/src/main/java/me/braydon/example/Main.java deleted file mode 100644 index 4f11dab..0000000 --- a/Example/src/main/java/me/braydon/example/Main.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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) { - 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; - } - // License is valid - System.out.println("License is valid!"); - if (response.getOwnerName() != null) { - System.out.println("Welcome " + response.getOwnerName() + "! Your plan is " + response.getPlan() + " and the latest version is " + response.getLatestVersion()); - } - if (response.getDescription() != null) { - System.out.println("Description: " + response.getDescription()); // License description - } - if (response.isPermanent()) { // License is permanent - System.out.println("Your license is permanent"); - } else { // License has an expiration date - System.out.printf("Your license will expire at: %s%n", response.getExpires().toInstant()); - } - } -} \ No newline at end of file