Add license actions
This commit is contained in:
parent
68591c90c9
commit
fec32230fe
8
pom.xml
8
pom.xml
@ -92,6 +92,14 @@
|
|||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Guava -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>32.0.0-jre</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring -->
|
<!-- Spring -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package me.braydon.license.service;
|
package me.braydon.license.service;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
import jakarta.annotation.Nonnull;
|
import jakarta.annotation.Nonnull;
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -18,11 +20,14 @@ import net.dv8tion.jda.api.entities.Activity;
|
|||||||
import net.dv8tion.jda.api.entities.MessageEmbed;
|
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||||
import net.dv8tion.jda.api.entities.User;
|
import net.dv8tion.jda.api.entities.User;
|
||||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||||
|
import net.dv8tion.jda.api.entities.emoji.Emoji;
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||||
|
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
|
||||||
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
|
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
|
||||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||||
import net.dv8tion.jda.api.interactions.commands.build.Commands;
|
import net.dv8tion.jda.api.interactions.commands.build.Commands;
|
||||||
|
import net.dv8tion.jda.api.interactions.components.buttons.Button;
|
||||||
import net.dv8tion.jda.api.requests.ErrorResponse;
|
import net.dv8tion.jda.api.requests.ErrorResponse;
|
||||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||||
import org.mindrot.jbcrypt.BCrypt;
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
@ -32,8 +37,10 @@ import org.springframework.boot.info.BuildProperties;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Braydon
|
* @author Braydon
|
||||||
@ -41,6 +48,9 @@ import java.util.Optional;
|
|||||||
@Service
|
@Service
|
||||||
@Slf4j(topic = "Discord")
|
@Slf4j(topic = "Discord")
|
||||||
public final class DiscordService {
|
public final class DiscordService {
|
||||||
|
private static final String CLEAR_IPS_BUTTON_ID = "clearIps";
|
||||||
|
private static final String CLEAR_HWIDS_BUTTON_ID = "clearHwids";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link LicenseRepository} to use.
|
* The {@link LicenseRepository} to use.
|
||||||
*/
|
*/
|
||||||
@ -116,10 +126,22 @@ public final class DiscordService {
|
|||||||
*/
|
*/
|
||||||
private JDA jda;
|
private JDA jda;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached licenses for messages.
|
||||||
|
* <p>
|
||||||
|
* When a license is looked up by it's owner, the
|
||||||
|
* response message is cached (key is the message snowflake)
|
||||||
|
* for 5 minutes. This is so we're able to get the message
|
||||||
|
* an action was performed on, as well as action timeouts.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
private final Cache<Long, License> cachedLicenses = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterWrite(5L, TimeUnit.MINUTES)
|
||||||
|
.build();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public DiscordService(@NonNull LicenseRepository licenseRepository, @NonNull BuildProperties buildProperties) {
|
public DiscordService(@NonNull LicenseRepository licenseRepository, @NonNull BuildProperties buildProperties) {
|
||||||
this.licenseRepository = licenseRepository;
|
this.licenseRepository = licenseRepository;
|
||||||
;
|
|
||||||
this.applicationVersion = buildProperties.getVersion();
|
this.applicationVersion = buildProperties.getVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,51 +275,109 @@ public final class DiscordService {
|
|||||||
if (event.getName().equals("license")) {
|
if (event.getName().equals("license")) {
|
||||||
String key = Objects.requireNonNull(event.getOption("key")).getAsString();
|
String key = Objects.requireNonNull(event.getOption("key")).getAsString();
|
||||||
String product = Objects.requireNonNull(event.getOption("product")).getAsString();
|
String product = Objects.requireNonNull(event.getOption("product")).getAsString();
|
||||||
event.deferReply().queue(); // Send thinking...
|
event.deferReply(true).queue(); // Send thinking...
|
||||||
|
|
||||||
// License lookup
|
// License lookup
|
||||||
Optional<License> optionalLicense = licenseRepository.getLicense(BCrypt.hashpw(key, licensesSalt), product);
|
try {
|
||||||
if (optionalLicense.isEmpty() // License not found or owned by someone else
|
Optional<License> optionalLicense = licenseRepository.getLicense(BCrypt.hashpw(key, licensesSalt), product);
|
||||||
|| (!optionalLicense.get().isOwner(user.getIdLong()))) {
|
if (optionalLicense.isEmpty() // License not found or owned by someone else
|
||||||
|
|| (!optionalLicense.get().isOwner(user.getIdLong()))) {
|
||||||
|
event.getHook().sendMessageEmbeds(buildEmbed(new EmbedBuilder()
|
||||||
|
.setColor(Color.RED)
|
||||||
|
.setTitle("License not found")
|
||||||
|
.setDescription("Could not locate the license you were looking for")
|
||||||
|
)).queue(); // Send the error message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
License license = optionalLicense.get(); // The found license
|
||||||
|
String obfuscateKey = MiscUtils.obfuscateKey(key); // Obfuscate the key
|
||||||
|
long expires = license.isPermanent() ? -1L : license.getExpires().getTime() / 1000L;
|
||||||
|
long lastUsed = license.getLastUsed() == null ? -1L : license.getExpires().getTime() / 1000L;
|
||||||
|
event.getHook().sendMessageEmbeds(buildEmbed(new EmbedBuilder()
|
||||||
|
.setColor(Color.BLUE)
|
||||||
|
.setTitle("Your License")
|
||||||
|
.addField("License", "`" + obfuscateKey + "`", true)
|
||||||
|
.addField("Product", license.getProduct(), true)
|
||||||
|
.addField("Description", license.getDescription(), true)
|
||||||
|
.addField("Expiration",
|
||||||
|
expires == -1L ? "Never" : "<t:" + expires + ":R>",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
.addField("Uses", String.valueOf(license.getUses()), true)
|
||||||
|
.addField("Last Used",
|
||||||
|
lastUsed == -1L ? "Never" : "<t:" + lastUsed + ":R>",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
.addField("IPs",
|
||||||
|
license.getIps().size() + "/" + license.getIpLimit(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
.addField("HWIDs",
|
||||||
|
license.getHwids().size() + "/" + license.getHwidLimit(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
.addField("Created",
|
||||||
|
"<t:" + (license.getCreated().getTime() / 1000L) + ":R>",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
)).addActionRow( // Buttons
|
||||||
|
Button.danger(CLEAR_IPS_BUTTON_ID, "Clear IPs")
|
||||||
|
.withEmoji(Emoji.fromUnicode("🗑️")),
|
||||||
|
Button.danger(CLEAR_HWIDS_BUTTON_ID, "Clear HWIDs")
|
||||||
|
.withEmoji(Emoji.fromUnicode("🗑️"))
|
||||||
|
).queue(message -> cachedLicenses.put(message.getIdLong(), license)); // Cache the license for the message
|
||||||
|
} catch (Exception ex) {
|
||||||
event.getHook().sendMessageEmbeds(buildEmbed(new EmbedBuilder()
|
event.getHook().sendMessageEmbeds(buildEmbed(new EmbedBuilder()
|
||||||
.setColor(Color.RED)
|
.setColor(Color.RED)
|
||||||
.setTitle("License not found")
|
.setTitle("Lookup Failed")
|
||||||
.setDescription("Could not locate the license you were looking for")
|
.setDescription("More information has been logged")
|
||||||
|
)).queue(); // Send the error message
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onButtonInteraction(@NonNull ButtonInteractionEvent event) {
|
||||||
|
User user = event.getUser(); // The user who clicked the button
|
||||||
|
String componentId = event.getComponentId(); // The button id
|
||||||
|
|
||||||
|
// License Actions
|
||||||
|
boolean clearIps = componentId.equals(CLEAR_IPS_BUTTON_ID);
|
||||||
|
boolean clearHwids = componentId.equals(CLEAR_HWIDS_BUTTON_ID);
|
||||||
|
if (clearIps || clearHwids) {
|
||||||
|
event.deferReply(true).queue(); // Send thinking...
|
||||||
|
License license = cachedLicenses.getIfPresent(event.getMessageIdLong()); // Get the cached license
|
||||||
|
if (license == null || (!license.isOwner(user.getIdLong()))) { // License not found or owned by someone else
|
||||||
|
event.getHook().sendMessageEmbeds(buildEmbed(new EmbedBuilder()
|
||||||
|
.setColor(Color.RED)
|
||||||
|
.setTitle("License Action Failed")
|
||||||
|
.setDescription("The license couldn't be found or the action timed out")
|
||||||
)).queue(); // Send the error message
|
)).queue(); // Send the error message
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
License license = optionalLicense.get(); // The found license
|
try {
|
||||||
String obfuscateKey = MiscUtils.obfuscateKey(key); // Obfuscate the key
|
// Clear IPs
|
||||||
long expires = license.isPermanent() ? -1L : license.getExpires().getTime() / 1000L;
|
if (clearIps) {
|
||||||
long lastUsed = license.getLastUsed() == null ? -1L : license.getExpires().getTime() / 1000L;
|
license.setIps(new HashSet<>());
|
||||||
event.getHook().sendMessageEmbeds(buildEmbed(new EmbedBuilder()
|
}
|
||||||
.setColor(Color.BLUE)
|
// Clear HWIDs
|
||||||
.setTitle("Your License")
|
if (clearHwids) {
|
||||||
.addField("License", "`" + obfuscateKey + "`", true)
|
license.setHwids(new HashSet<>());
|
||||||
.addField("Product", license.getProduct(), true)
|
}
|
||||||
.addField("Description", license.getDescription(), true)
|
licenseRepository.save(license); // Save the license
|
||||||
.addField("Expiration",
|
event.getHook().sendMessageEmbeds(buildEmbed(new EmbedBuilder()
|
||||||
expires == -1L ? "Never" : "<t:" + expires + ":R>",
|
.setColor(Color.GREEN)
|
||||||
true
|
.setTitle("Cleared " + (clearIps ? "IP" : "HWID") + "s")
|
||||||
)
|
)).queue(); // Inform action success
|
||||||
.addField("Uses", String.valueOf(license.getUses()), true)
|
} catch (Exception ex) {
|
||||||
.addField("Last Used",
|
event.getHook().sendMessageEmbeds(buildEmbed(new EmbedBuilder()
|
||||||
lastUsed == -1L ? "Never" : "<t:" + lastUsed + ":R>",
|
.setColor(Color.RED)
|
||||||
true
|
.setTitle("License Action Failed")
|
||||||
)
|
.setDescription("More information has been logged")
|
||||||
.addField("IPs",
|
)).queue(); // Send the error message
|
||||||
license.getIps().size() + "/" + license.getIpLimit(),
|
ex.printStackTrace();
|
||||||
true
|
}
|
||||||
)
|
|
||||||
.addField("HWIDs",
|
|
||||||
license.getHwids().size() + "/" + license.getHwidLimit(),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
.addField("Created",
|
|
||||||
"<t:" + (license.getCreated().getTime() / 1000L) + ":R>",
|
|
||||||
true
|
|
||||||
)
|
|
||||||
)).queue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user