Replace guild access with owner-managed whitelist
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ COPY src/ ./
|
|||||||
RUN dotnet publish -c Release -r linux-musl-x64 --self-contained true -o /out
|
RUN dotnet publish -c Release -r linux-musl-x64 --self-contained true -o /out
|
||||||
|
|
||||||
FROM alpine:3.23
|
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
|
COPY --from=build /out/Beetlejuice /usr/local/bin/beetlejuice
|
||||||
USER 65532:65532
|
USER 65532:65532
|
||||||
ENTRYPOINT ["/usr/local/bin/beetlejuice"]
|
ENTRYPOINT ["/usr/local/bin/beetlejuice"]
|
||||||
|
|||||||
+27
-4
@@ -13,8 +13,12 @@ string Env(string key, string? fallback = null) => Environment.GetEnvironmentVar
|
|||||||
?? throw new InvalidOperationException($"Missing {key}");
|
?? throw new InvalidOperationException($"Missing {key}");
|
||||||
string discordToken = Env("DISCORD_TOKEN");
|
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; }
|
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"));
|
const ulong initialUser = 227696176412098560;
|
||||||
var roles = Env("DISCORD_ALLOWED_ROLE_IDS", "").Split(',', StringSplitOptions.RemoveEmptyEntries).Select(ulong.Parse).ToHashSet();
|
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");
|
string rconPassword = Env("RCON_PASSWORD");
|
||||||
if (rconPassword.Length != 64) throw new InvalidOperationException("RCON_PASSWORD must be 64 characters");
|
if (rconPassword.Length != 64) throw new InvalidOperationException("RCON_PASSWORD must be 64 characters");
|
||||||
var zone = TimeZoneInfo.FindSystemTimeZoneById(Env("AUTO_RESTART_TIMEZONE", "Australia/Brisbane"));
|
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();
|
.AddApplicationCommands();
|
||||||
var host = builder.Build();
|
var host = builder.Build();
|
||||||
|
|
||||||
bool Allowed(ApplicationCommandContext c) => c.Interaction.GuildId == guildId && c.User is GuildInteractionUser u &&
|
bool Allowed(ApplicationCommandContext c) { lock (whitelistLock) return whitelist.Contains(c.User.Id); }
|
||||||
(roles.Count == 0 || u.RoleIds.Any(roles.Contains));
|
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)
|
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);
|
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."));
|
Allowed(c) ? Manual() : Task.FromResult("Not authorised."));
|
||||||
host.AddSlashCommand("players", "List online players", async (ApplicationCommandContext c) =>
|
host.AddSlashCommand("players", "List online players", async (ApplicationCommandContext c) =>
|
||||||
!Allowed(c) ? "Not authorised." : await PlayerList());
|
!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> Status() { try { return $"Server online; {(await Players()).Count} player(s)."; } catch { return "Server unavailable."; } }
|
||||||
async Task<string> PlayerList()
|
async Task<string> PlayerList()
|
||||||
|
|||||||
Reference in New Issue
Block a user