diff --git a/src/main/java/me/braydon/license/exception/LicenseExpiredException.java b/src/main/java/me/braydon/license/exception/LicenseExpiredException.java new file mode 100644 index 0000000..03268bd --- /dev/null +++ b/src/main/java/me/braydon/license/exception/LicenseExpiredException.java @@ -0,0 +1,17 @@ +package me.braydon.license.exception; + +import me.braydon.license.model.License; +import org.springframework.http.HttpStatus; + +/** + * This exception is raised when + * a {@link License} has been used + * but is expired. + * + * @author Braydon + */ +public class LicenseExpiredException extends APIException { + public LicenseExpiredException() { + super(HttpStatus.BAD_REQUEST, "License has expired"); + } +} diff --git a/src/main/java/me/braydon/license/model/License.java b/src/main/java/me/braydon/license/model/License.java index b29aaca..c642c91 100644 --- a/src/main/java/me/braydon/license/model/License.java +++ b/src/main/java/me/braydon/license/model/License.java @@ -64,6 +64,14 @@ public class License { */ private int hwidLimit; + /** + * The duration that this licensee is valid for. + *

+ * If -1, the license will be permanent. + *

+ */ + private long duration; + /** * The {@link Date} this license was last used. */ @@ -74,6 +82,34 @@ public class License { */ @NonNull private Date created; + /** + * Check if this license has expired. + *

+ * If this license has no + * expiration, this will + * always return false. + *

+ * + * @return true if expired, otherwise false + */ + public boolean hasExpired() { + // License is permanent, not expired + if (isPermanent()) { + return false; + } + // Check if the license has expired + return System.currentTimeMillis() - created.getTime() >= duration; + } + + /** + * Check if this license has no expiration. + * + * @return true if permanent, otherwise false + */ + public boolean isPermanent() { + return duration == -1L; + } + /** * Invoked when this license is used. * diff --git a/src/main/java/me/braydon/license/service/LicenseService.java b/src/main/java/me/braydon/license/service/LicenseService.java index 90da960..ed4c172 100644 --- a/src/main/java/me/braydon/license/service/LicenseService.java +++ b/src/main/java/me/braydon/license/service/LicenseService.java @@ -4,6 +4,7 @@ import jakarta.annotation.PostConstruct; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import me.braydon.license.exception.APIException; +import me.braydon.license.exception.LicenseExpiredException; import me.braydon.license.exception.LicenseNotFoundException; import me.braydon.license.model.License; import me.braydon.license.repository.LicenseRepository; @@ -66,11 +67,12 @@ public final class LicenseService { * @param description the optional description of the license * @param ipLimit the IP limit of the license * @param hwidLimit the HWID limit of the license + * @param duration the duration of the license, -1 for permanent * @return the created license * @see License for license */ - public License create(@NonNull String key, @NonNull String product, - String description, int ipLimit, int hwidLimit) { + public License create(@NonNull String key, @NonNull String product, String description, + int ipLimit, int hwidLimit, long duration) { // Create the new license License license = new License(); license.setKey(BCrypt.hashpw(key, licensesSalt)); // Hash the key @@ -80,6 +82,7 @@ public final class LicenseService { license.setHwids(new HashSet<>()); license.setIpLimit(ipLimit); // Use the given IP limit license.setHwidLimit(hwidLimit); // Use the given HWID limit + license.setDuration(duration); license.setCreated(new Date()); repository.insert(license); // Insert the newly created license return license; @@ -103,6 +106,9 @@ public final class LicenseService { throw new LicenseNotFoundException(); } License license = optionalLicense.get(); // The license found + if (license.hasExpired()) { // The license has expired + throw new LicenseExpiredException(); + } license.use(ip, ipsSalt, hwid); // Use the license repository.save(license); // Save the used license log.info("License key {} for product {} was used by {} ({})", key, product, ip, hwid);