Hash IP addresses

This commit is contained in:
Braydon 2023-05-31 02:16:13 -04:00
parent a5a154610e
commit 3412668ec1
3 changed files with 28 additions and 18 deletions

@ -7,6 +7,7 @@ import lombok.ToString;
import me.braydon.license.exception.APIException; import me.braydon.license.exception.APIException;
import me.braydon.license.exception.LicenseHwidLimitExceededException; import me.braydon.license.exception.LicenseHwidLimitExceededException;
import me.braydon.license.exception.LicenseIpLimitExceededException; import me.braydon.license.exception.LicenseIpLimitExceededException;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Document;
@ -45,9 +46,6 @@ public class License {
/** /**
* The IPs used on this license. * The IPs used on this license.
* <p>
* These IPs are encrypted using AES-256.
* </p>
*/ */
private Set<String> ips; private Set<String> ips;
@ -80,18 +78,23 @@ public class License {
* Invoked when this license is used. * Invoked when this license is used.
* *
* @param ip the ip used * @param ip the ip used
* @param ipSalt the IP salt to use
* @param hwid the hardware id used * @param hwid the hardware id used
*/ */
public void use(@NonNull String ip, @NonNull String hwid) throws APIException { public void use(@NonNull String ip, @NonNull String ipSalt, @NonNull String hwid) throws APIException {
if (!ips.contains(ip) && ips.size() >= ipLimit) { // IP limit has been exceeded String hashedIp = BCrypt.hashpw(ip, ipSalt); // Hash the IP
// IP limit has been exceeded
if (!ips.contains(hashedIp) && ips.size() >= ipLimit) {
throw new LicenseIpLimitExceededException(); throw new LicenseIpLimitExceededException();
} }
if (!hwids.contains(hwid) && hwids.size() >= hwidLimit) { // HWID limit has been exceeded // HWID limit has been exceeded
if (!hwids.contains(hwid) && hwids.size() >= hwidLimit) {
throw new LicenseHwidLimitExceededException(); throw new LicenseHwidLimitExceededException();
} }
// The license was used // The license was used
uses++; // Increment uses uses++; // Increment uses
ips.add(ip); // Add the used IP ips.add(hashedIp); // Add the used IP
hwids.add(hwid); // Add the used HWID hwids.add(hwid); // Add the used HWID
lastUsed = new Date(); // Last used now lastUsed = new Date(); // Last used now
} }

@ -3,7 +3,6 @@ package me.braydon.license.service;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.braydon.license.common.RandomUtils;
import me.braydon.license.exception.APIException; import me.braydon.license.exception.APIException;
import me.braydon.license.exception.LicenseNotFoundException; import me.braydon.license.exception.LicenseNotFoundException;
import me.braydon.license.model.License; import me.braydon.license.model.License;
@ -33,8 +32,14 @@ public final class LicenseService {
/** /**
* The salt to use for hashing license keys. * The salt to use for hashing license keys.
*/ */
@Value("${key-salt}") @Value("${salts.licenses}")
@NonNull private String keySalt; @NonNull private String licensesSalt;
/**
* The salt to use for hashing IP addresses.
*/
@Value("${salts.ips}")
@NonNull private String ipsSalt;
@Autowired @Autowired
public LicenseService(@NonNull LicenseRepository repository) { public LicenseService(@NonNull LicenseRepository repository) {
@ -68,7 +73,7 @@ public final class LicenseService {
String description, int ipLimit, int hwidLimit) { String description, int ipLimit, int hwidLimit) {
// Create the new license // Create the new license
License license = new License(); License license = new License();
license.setKey(BCrypt.hashpw(key, keySalt)); // Hash the key license.setKey(BCrypt.hashpw(key, licensesSalt)); // Hash the key
license.setProduct(product); // Use the given product license.setProduct(product); // Use the given product
license.setDescription(description); // Use the given description, if any license.setDescription(description); // Use the given description, if any
license.setIps(new HashSet<>()); license.setIps(new HashSet<>());
@ -92,13 +97,13 @@ public final class LicenseService {
*/ */
public void check(@NonNull String key, @NonNull String product, public void check(@NonNull String key, @NonNull String product,
@NonNull String ip, @NonNull String hwid) throws APIException { @NonNull String ip, @NonNull String hwid) throws APIException {
Optional<License> optionalLicense = repository.getLicense(BCrypt.hashpw(key, keySalt), product); // Get the license Optional<License> optionalLicense = repository.getLicense(BCrypt.hashpw(key, licensesSalt), product); // Get the license
if (optionalLicense.isEmpty()) { // License key not found if (optionalLicense.isEmpty()) { // License key not found
log.error("License key {} for product {} not found", key, product); // Log the error log.error("License key {} for product {} not found", key, product); // Log the error
throw new LicenseNotFoundException(); throw new LicenseNotFoundException();
} }
License license = optionalLicense.get(); // The license found License license = optionalLicense.get(); // The license found
license.use(ip, hwid); // Use the license license.use(ip, ipsSalt, hwid); // Use the license
repository.save(license); // Save the used license repository.save(license); // Save the used license
log.info("License key {} for product {} was used by {} ({})", key, product, ip, hwid); log.info("License key {} for product {} was used by {} ({})", key, product, ip, hwid);
} }

@ -3,9 +3,11 @@ server:
address: 0.0.0.0 address: 0.0.0.0
port: 7500 port: 7500
# The salt to use when hashing license keys. # The salt to use when hashing license keys and IP addresses.
# This salt should be changed from the default. # These salts should be changed from the default.
key-salt: "$2a$10$/nQyzQDMkCf97ZlJLLWa3O" salts:
licenses: "$2a$10$/nQyzQDMkCf97ZlJLLWa3O"
ips: "$2a$10$Xus.AHTCas97Ofx0tFs85O"
# Log Configuration # Log Configuration
logging: logging: