Replace guild access with owner-managed whitelist

This commit is contained in:
MrDevBot
2026-09-01 19:19:24 +10:00
parent e2a3380e4e
commit 5650d1d49a
2 changed files with 28 additions and 5 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ COPY src/ ./
RUN dotnet publish -c Release -r linux-musl-x64 --self-contained true -o /out
FROM alpine:3.23
RUN apk add --no-cache ca-certificates tzdata libgcc libstdc++
RUN apk add --no-cache ca-certificates tzdata libgcc libstdc++ && mkdir /data && chown 65532:65532 /data
COPY --from=build /out/Beetlejuice /usr/local/bin/beetlejuice
USER 65532:65532
ENTRYPOINT ["/usr/local/bin/beetlejuice"]
+27 -4
View File
@@ -13,8 +13,12 @@ string Env(string key, string? fallback = null) => Environment.GetEnvironmentVar
?? throw new InvalidOperationException($"Missing {key}");
string discordToken = Env("DISCORD_TOKEN");
if (discordToken == "REPLACE_IN_COOLIFY") { Console.WriteLine("Set DISCORD_TOKEN in Coolify, then restart Beetlejuice."); await Task.Delay(Timeout.Infinite); return; }
ulong guildId = ulong.Parse(Env("DISCORD_GUILD_ID"));
var roles = Env("DISCORD_ALLOWED_ROLE_IDS", "").Split(',', StringSplitOptions.RemoveEmptyEntries).Select(ulong.Parse).ToHashSet();
const ulong initialUser = 227696176412098560;
string whitelistPath = Env("WHITELIST_PATH", "/data/whitelist");
Directory.CreateDirectory(Path.GetDirectoryName(whitelistPath)!);
var whitelist = File.Exists(whitelistPath) ? File.ReadAllLines(whitelistPath).Select(ulong.Parse).ToHashSet() : [initialUser];
if (!File.Exists(whitelistPath)) File.WriteAllLines(whitelistPath, whitelist.Select(x => x.ToString()));
var whitelistLock = new object();
string rconPassword = Env("RCON_PASSWORD");
if (rconPassword.Length != 64) throw new InvalidOperationException("RCON_PASSWORD must be 64 characters");
var zone = TimeZoneInfo.FindSystemTimeZoneById(Env("AUTO_RESTART_TIMEZONE", "Australia/Brisbane"));
@@ -30,8 +34,22 @@ builder.Services.AddDiscordGateway(o => { o.Token = discordToken; o.Intents = Ga
.AddApplicationCommands();
var host = builder.Build();
bool Allowed(ApplicationCommandContext c) => c.Interaction.GuildId == guildId && c.User is GuildInteractionUser u &&
(roles.Count == 0 || u.RoleIds.Any(roles.Contains));
bool Allowed(ApplicationCommandContext c) { lock (whitelistLock) return whitelist.Contains(c.User.Id); }
string Whitelist(ApplicationCommandContext c, string discordId, bool add)
{
if (c.User.Id != initialUser) return "Not authorised.";
if (!ulong.TryParse(discordId, out ulong id)) return "Invalid Discord ID.";
if (!add && id == initialUser) return "The whitelist owner cannot be removed.";
lock (whitelistLock)
{
bool changed = add ? whitelist.Add(id) : whitelist.Remove(id);
if (!changed) return add ? "Already whitelisted." : "Not whitelisted.";
string temp = whitelistPath + ".tmp";
File.WriteAllLines(temp, whitelist.Order().Select(x => x.ToString()));
File.Move(temp, whitelistPath, true);
return $"{(add ? "Added" : "Removed")} <@{id}>.";
}
}
async Task<string> Command(string command, bool allowDisconnect = false)
{
var address = (await Dns.GetHostAddressesAsync(Env("RCON_HOST", "zomboid"))).First(x => x.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
@@ -129,6 +147,11 @@ host.AddSlashCommand("restart", "Restart when no players are online", (Applicati
Allowed(c) ? Manual() : Task.FromResult("Not authorised."));
host.AddSlashCommand("players", "List online players", async (ApplicationCommandContext c) =>
!Allowed(c) ? "Not authorised." : await PlayerList());
host.AddSlashCommandGroup("whitelist", "Manage bot access", group =>
{
group.AddSubCommand("add", "Add a Discord user", (string discordId, ApplicationCommandContext c) => Whitelist(c, discordId, true));
group.AddSubCommand("del", "Remove a Discord user", (string discordId, ApplicationCommandContext c) => Whitelist(c, discordId, false));
});
async Task<string> Status() { try { return $"Server online; {(await Players()).Count} player(s)."; } catch { return "Server unavailable."; } }
async Task<string> PlayerList()