Implement random.org API integration with random seed updater
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
b81a7e65d2
commit
d7aa5d75eb
16
pom.xml
16
pom.xml
@ -55,7 +55,21 @@
|
|||||||
<artifactId>json</artifactId>
|
<artifactId>json</artifactId>
|
||||||
<version>20220924</version>
|
<version>20220924</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jinahya</groupId>
|
||||||
|
<artifactId>random-org-json-rpc</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.10.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
<version>1.15</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package wtf.beatrice.hidekobot;
|
package wtf.beatrice.hidekobot;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.random.util.RandomOrgRandom;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import wtf.beatrice.hidekobot.datasources.ConfigurationEntry;
|
import wtf.beatrice.hidekobot.datasources.ConfigurationEntry;
|
||||||
@ -31,7 +32,7 @@ public class Cache
|
|||||||
|
|
||||||
// the Random instance that we should always use when looking for an RNG based thing.
|
// the Random instance that we should always use when looking for an RNG based thing.
|
||||||
// the seed is updated periodically.
|
// the seed is updated periodically.
|
||||||
private static final SecureRandom randomInstance = new SecureRandom();
|
private static Random randomInstance = new SecureRandom();
|
||||||
|
|
||||||
// map to store results of "love calculator", to avoid people re-running the same command until
|
// map to store results of "love calculator", to avoid people re-running the same command until
|
||||||
// they get what they wanted.
|
// they get what they wanted.
|
||||||
@ -86,8 +87,22 @@ public class Cache
|
|||||||
return randomInstance;
|
return randomInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setRandomSeed(long seed) {
|
public static void initRandomOrg(String apiKey)
|
||||||
randomInstance.setSeed(seed);
|
{
|
||||||
|
/* we use the random.org instance to generate 160 random bytes.
|
||||||
|
then, we're feeding those 160 bytes as a seed for a SecureRandom.
|
||||||
|
|
||||||
|
this is preferred to calling the RandomOrgRandom directly every time,
|
||||||
|
because it has to query the api and (1) takes a long time, especially with big
|
||||||
|
dice rolls, and (2) you'd run in the limits extremely quickly if the bot
|
||||||
|
was run publicly for everyone to use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
RandomOrgRandom randomOrg = new RandomOrgRandom(apiKey);
|
||||||
|
byte[] randomBytes = new byte[160];
|
||||||
|
randomOrg.nextBytes(randomBytes);
|
||||||
|
|
||||||
|
randomInstance = new SecureRandom(randomBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,6 +158,10 @@ public class Cache
|
|||||||
return configurationSource == null ? null : (String) configurationSource.getConfigValue(ConfigurationEntry.BOT_TOKEN);
|
return configurationSource == null ? null : (String) configurationSource.getConfigValue(ConfigurationEntry.BOT_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getRandomOrgApiKey() {
|
||||||
|
return configurationSource == null ? null : (String) configurationSource.getConfigValue(ConfigurationEntry.RANDOM_ORG_API_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the bot maintainer's profile id.
|
* Get the bot maintainer's profile id.
|
||||||
*
|
*
|
||||||
|
@ -10,12 +10,14 @@ import sun.misc.Signal;
|
|||||||
import wtf.beatrice.hidekobot.commands.completer.ProfileImageCommandCompleter;
|
import wtf.beatrice.hidekobot.commands.completer.ProfileImageCommandCompleter;
|
||||||
import wtf.beatrice.hidekobot.commands.message.HelloCommand;
|
import wtf.beatrice.hidekobot.commands.message.HelloCommand;
|
||||||
import wtf.beatrice.hidekobot.commands.slash.*;
|
import wtf.beatrice.hidekobot.commands.slash.*;
|
||||||
|
import wtf.beatrice.hidekobot.datasources.ConfigurationEntry;
|
||||||
import wtf.beatrice.hidekobot.datasources.ConfigurationSource;
|
import wtf.beatrice.hidekobot.datasources.ConfigurationSource;
|
||||||
import wtf.beatrice.hidekobot.datasources.DatabaseSource;
|
import wtf.beatrice.hidekobot.datasources.DatabaseSource;
|
||||||
import wtf.beatrice.hidekobot.datasources.PropertiesSource;
|
import wtf.beatrice.hidekobot.datasources.PropertiesSource;
|
||||||
import wtf.beatrice.hidekobot.listeners.*;
|
import wtf.beatrice.hidekobot.listeners.*;
|
||||||
import wtf.beatrice.hidekobot.runnables.ExpiredMessageTask;
|
import wtf.beatrice.hidekobot.runnables.ExpiredMessageTask;
|
||||||
import wtf.beatrice.hidekobot.runnables.HeartBeatTask;
|
import wtf.beatrice.hidekobot.runnables.HeartBeatTask;
|
||||||
|
import wtf.beatrice.hidekobot.runnables.RandomOrgSeedTask;
|
||||||
import wtf.beatrice.hidekobot.runnables.StatusUpdateTask;
|
import wtf.beatrice.hidekobot.runnables.StatusUpdateTask;
|
||||||
import wtf.beatrice.hidekobot.util.CommandUtil;
|
import wtf.beatrice.hidekobot.util.CommandUtil;
|
||||||
import wtf.beatrice.hidekobot.util.FormatUtil;
|
import wtf.beatrice.hidekobot.util.FormatUtil;
|
||||||
@ -107,6 +109,22 @@ public class HidekoBot
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boolean enableRandomSeedUpdaterTask = false;
|
||||||
|
// initialize random.org object if API key is provided
|
||||||
|
{
|
||||||
|
String apiKey = Cache.getRandomOrgApiKey();
|
||||||
|
if(apiKey != null &&
|
||||||
|
!apiKey.isEmpty() &&
|
||||||
|
!apiKey.equals(ConfigurationEntry.RANDOM_ORG_API_KEY.getDefaultValue()))
|
||||||
|
{
|
||||||
|
LOGGER.info("Enabling Random.org integration... This might take a while!");
|
||||||
|
Cache.initRandomOrg(apiKey);
|
||||||
|
enableRandomSeedUpdaterTask = true;
|
||||||
|
LOGGER.info("Random.org integration enabled!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// register slash commands and completers
|
// register slash commands and completers
|
||||||
SlashCommandListener slashCommandListener = new SlashCommandListener();
|
SlashCommandListener slashCommandListener = new SlashCommandListener();
|
||||||
SlashCommandCompletionListener slashCommandCompletionListener = new SlashCommandCompletionListener();
|
SlashCommandCompletionListener slashCommandCompletionListener = new SlashCommandCompletionListener();
|
||||||
@ -198,6 +216,11 @@ public class HidekoBot
|
|||||||
scheduler.scheduleAtFixedRate(heartBeatTask, 10L, 30L, TimeUnit.SECONDS); //every 30 seconds
|
scheduler.scheduleAtFixedRate(heartBeatTask, 10L, 30L, TimeUnit.SECONDS); //every 30 seconds
|
||||||
StatusUpdateTask statusUpdateTask = new StatusUpdateTask();
|
StatusUpdateTask statusUpdateTask = new StatusUpdateTask();
|
||||||
scheduler.scheduleAtFixedRate(statusUpdateTask, 0L, 60L * 5L, TimeUnit.SECONDS); // every 5 minutes
|
scheduler.scheduleAtFixedRate(statusUpdateTask, 0L, 60L * 5L, TimeUnit.SECONDS); // every 5 minutes
|
||||||
|
if(enableRandomSeedUpdaterTask)
|
||||||
|
{
|
||||||
|
RandomOrgSeedTask randomSeedTask = new RandomOrgSeedTask();
|
||||||
|
scheduler.scheduleAtFixedRate(randomSeedTask, 15L, 15L, TimeUnit.MINUTES); // every 15 minutes
|
||||||
|
}
|
||||||
|
|
||||||
// register shutdown interrupt signal listener for proper shutdown.
|
// register shutdown interrupt signal listener for proper shutdown.
|
||||||
Signal.handle(new Signal("INT"), signal -> shutdown());
|
Signal.handle(new Signal("INT"), signal -> shutdown());
|
||||||
|
@ -2,6 +2,7 @@ package wtf.beatrice.hidekobot.commands.base;
|
|||||||
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
import net.dv8tion.jda.api.EmbedBuilder;
|
||||||
import net.dv8tion.jda.api.entities.User;
|
import net.dv8tion.jda.api.entities.User;
|
||||||
|
import org.random.util.RandomOrgRandom;
|
||||||
import wtf.beatrice.hidekobot.Cache;
|
import wtf.beatrice.hidekobot.Cache;
|
||||||
import wtf.beatrice.hidekobot.objects.MessageResponse;
|
import wtf.beatrice.hidekobot.objects.MessageResponse;
|
||||||
import wtf.beatrice.hidekobot.objects.fun.Dice;
|
import wtf.beatrice.hidekobot.objects.fun.Dice;
|
||||||
@ -125,6 +126,9 @@ public class DiceRoll
|
|||||||
embedBuilder.setAuthor(author.getAsTag(), null, author.getAvatarUrl());
|
embedBuilder.setAuthor(author.getAsTag(), null, author.getAvatarUrl());
|
||||||
embedBuilder.setTitle("Dice Roll");
|
embedBuilder.setTitle("Dice Roll");
|
||||||
|
|
||||||
|
if(Cache.getRandom() instanceof RandomOrgRandom)
|
||||||
|
embedBuilder.setFooter("Seed provided by Random.org");
|
||||||
|
|
||||||
StringBuilder message = new StringBuilder();
|
StringBuilder message = new StringBuilder();
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ public enum ConfigurationEntry
|
|||||||
BOT_OWNER_ID("bot-owner-id", 100000000000000000L),
|
BOT_OWNER_ID("bot-owner-id", 100000000000000000L),
|
||||||
BOT_COLOR("bot-color", "PINK"),
|
BOT_COLOR("bot-color", "PINK"),
|
||||||
HEARTBEAT_LINK("heartbeat-link", "https://your-heartbeat-api.com/api/push/apikey?status=up&msg=OK&ping="),
|
HEARTBEAT_LINK("heartbeat-link", "https://your-heartbeat-api.com/api/push/apikey?status=up&msg=OK&ping="),
|
||||||
|
RANDOM_ORG_API_KEY("random-org-api-key", "00000000-0000-0000-0000-000000000000"),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package wtf.beatrice.hidekobot.runnables;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import wtf.beatrice.hidekobot.Cache;
|
||||||
|
import wtf.beatrice.hidekobot.datasources.ConfigurationEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This runnable pulls a random seed from random.org and used it to feed a SecureRandom,
|
||||||
|
* if the integration is enabled.
|
||||||
|
* <br/>
|
||||||
|
* This is necessary since we are not directly accessing random.org for each random number we
|
||||||
|
* need, and thus, only the seed is random - not the algorithm applied to it to compute the numbers.
|
||||||
|
*/
|
||||||
|
public class RandomOrgSeedTask implements Runnable
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(RandomOrgSeedTask.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
String apiKey = Cache.getRandomOrgApiKey();
|
||||||
|
if(apiKey != null &&
|
||||||
|
!apiKey.isEmpty() &&
|
||||||
|
!apiKey.equals(ConfigurationEntry.RANDOM_ORG_API_KEY.getDefaultValue()))
|
||||||
|
{
|
||||||
|
if(Cache.isVerbose()) LOGGER.info("Updating Random seed from random.org...");
|
||||||
|
Cache.initRandomOrg(Cache.getRandomOrgApiKey());
|
||||||
|
if(Cache.isVerbose()) LOGGER.info("Random.org seed updated!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user