Skip to content

Commit

Permalink
add commands: ban stage <stage-name> and unban stage <stage-name>
Browse files Browse the repository at this point in the history
To kick players from the server when they enter a banned stage.

<stage-name> can also be a kingdom alias, which bans/unbans all stages in that kingdom.

Because we aren't banning the player, d/c them would be no good, because of the client auto reconnect.
Instead send them the crash and ignore all packets by them until they d/c on their own.

This is an alternative solution for issue Sanae6#43.
  • Loading branch information
Istador committed Mar 24, 2023
1 parent 7082f28 commit bf0bfae
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 7 deletions.
84 changes: 78 additions & 6 deletions Server/BanLists.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Net.Sockets;
using System.Text;

using Shared;
using Shared.Packet.Packets;

namespace Server;
Expand Down Expand Up @@ -30,6 +31,12 @@ private static ISet<Guid> Profiles {
}
}

private static ISet<string> Stages {
get {
return Settings.Instance.BanList.Stages;
}
}


private static bool IsIPv4(string str) {
return IPAddress.TryParse(str, out IPAddress? ip)
Expand Down Expand Up @@ -62,6 +69,10 @@ public static bool IsProfileBanned(Guid id) {
return Profiles.Contains(id);
}

public static bool IsStageBanned(string stage) {
return Stages.Contains(stage);
}

public static bool IsClientBanned(Client user) {
return IsProfileBanned(user) || IsIPv4Banned(user);
}
Expand Down Expand Up @@ -91,6 +102,10 @@ private static void BanProfile(Guid id) {
Profiles.Add(id);
}

private static void BanStage(string stage) {
Stages.Add(stage);
}

private static void BanClient(Client user) {
BanProfile(user);
BanIPv4(user);
Expand Down Expand Up @@ -121,22 +136,36 @@ private static void UnbanProfile(Guid id) {
Profiles.Remove(id);
}

private static void UnbanStage(string stage) {
Stages.Remove(stage);
}


private static void Save() {
Settings.SaveSettings(true);
}


public static void Crash(Client user, bool permanent = false) {
public static void Crash(
Client user,
bool permanent = false,
bool dispose_user = true,
int delay_ms = 0
) {
user.Ignored = true;
Task.Run(async () => {
if (delay_ms > 0) {
await Task.Delay(delay_ms);
}
await user.Send(new ChangeStagePacket {
Id = (permanent ? "$agogus/ban4lyfe" : "$among$us/cr4sh%"),
Stage = (permanent ? "$ejected" : "$agogusStage"),
Scenario = (sbyte) (permanent ? 69 : 21),
SubScenarioType = (byte) (permanent ? 21 : 69),
});
user.Dispose();
if (dispose_user) {
user.Dispose();
}
});
}

Expand All @@ -149,15 +178,15 @@ private static void CrashMultiple(string[] args, MUCH much) {

public static string HandleBanCommand(string[] args, MUCH much) {
if (args.Length == 0) {
return "Usage: ban {list|enable|disable|player|profile|ip} ...";
return "Usage: ban {list|enable|disable|player|profile|ip|stage} ...";
}

string cmd = args[0];
args = args.Skip(1).ToArray();

switch (cmd) {
default:
return "Usage: ban {list|enable|disable|player|profile|ip} ...";
return "Usage: ban {list|enable|disable|player|profile|ip|stage} ...";

case "list":
if (args.Length != 0) {
Expand All @@ -176,6 +205,11 @@ public static string HandleBanCommand(string[] args, MUCH much) {
list.Append(string.Join("\n- ", Profiles));
}

if (Stages.Count > 0) {
list.Append("\nBanned stages:\n- ");
list.Append(string.Join("\n- ", Stages));
}

return list.ToString();

case "enable":
Expand Down Expand Up @@ -247,21 +281,43 @@ public static string HandleBanCommand(string[] args, MUCH much) {
CrashMultiple(args, much);
Save();
return "Banned ip: " + args[0];

case "stage":
if (args.Length != 1) {
return "Usage: ban stage <stage-name>";
}
string? stage = Shared.Stages.Input2Stage(args[0]);
if (stage == null) {
return "Invalid stage name!";
}
if (IsStageBanned(stage)) {
return "Stage " + stage + " is already banned.";
}
var stages = Shared.Stages
.StagesByInput(args[0])
.Where(s => !IsStageBanned(s))
.ToList()
;
foreach (string s in stages) {
BanStage(s);
}
Save();
return "Banned stage: " + string.Join(", ", stages);
}
}


public static string HandleUnbanCommand(string[] args) {
if (args.Length != 2) {
return "Usage: unban {profile|ip} <value>";
return "Usage: unban {profile|ip|stage} <value>";
}

string cmd = args[0];
string val = args[1];

switch (cmd) {
default:
return "Usage: unban {profile|ip} <value>";
return "Usage: unban {profile|ip|stage} <value>";

case "profile":
if (!Guid.TryParse(val, out Guid id)) {
Expand All @@ -284,6 +340,22 @@ public static string HandleUnbanCommand(string[] args) {
UnbanIPv4(val);
Save();
return "Unbanned ip: " + val;

case "stage":
string stage = Shared.Stages.Input2Stage(val) ?? val;
if (!IsStageBanned(stage)) {
return "Stage " + stage + " is not banned.";
}
var stages = Shared.Stages
.StagesByInput(val)
.Where(IsStageBanned)
.ToList()
;
foreach (string s in stages) {
UnbanStage(s);
}
Save();
return "Unbanned stage: " + string.Join(", ", stages);
}
}
}
5 changes: 5 additions & 0 deletions Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ async void SyncShineBag() {
server.PacketHandler = (c, p) => {
switch (p) {
case GamePacket gamePacket: {
if (BanLists.Enabled && BanLists.IsStageBanned(gamePacket.Stage)) {
c.Logger.Warn($"Crashing player for entering banned stage {gamePacket.Stage}.");
BanLists.Crash(c, false, false, 500);
return false;
}
c.Logger.Info($"Got game packet {gamePacket.Stage}->{gamePacket.ScenarioNum}");
c.Metadata["scenario"] = gamePacket.ScenarioNum;
c.Metadata["2d"] = gamePacket.Is2d;
Expand Down
1 change: 1 addition & 0 deletions Server/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class BanListTable {
public bool Enabled { get; set; } = false;
public ISet<Guid> Players { get; set; } = new SortedSet<Guid>();
public ISet<string> IpAddresses { get; set; } = new SortedSet<string>();
public ISet<string> Stages { get; set; } = new SortedSet<string>();
}

public class FlipTable {
Expand Down
28 changes: 27 additions & 1 deletion Shared/Stages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static class Stages {
return mapName;
}
// exact stage value
if (Stage2Alias.ContainsKey(input)) {
if (IsStage(input)) {
return input;
}
// force input value with a !
Expand All @@ -29,6 +29,32 @@ public static string KingdomAliasMapping() {
return result;
}

public static bool IsAlias(string input) {
return Alias2Stage.ContainsKey(input);
}

public static bool IsStage(string input) {
return Stage2Alias.ContainsKey(input);
}

public static IEnumerable<string> StagesByInput(string input) {
if (IsAlias(input)) {
var stages = Stage2Alias
.Where(e => e.Value == input)
.Select(e => e.Key)
;
foreach (string stage in stages) {
yield return stage;
}
}
else {
string? stage = Input2Stage(input);
if (stage != null) {
yield return stage;
}
}
}

public static readonly Dictionary<string, string> Alias2Stage = new Dictionary<string, string>() {
{ "cap", "CapWorldHomeStage" },
{ "cascade", "WaterfallWorldHomeStage" },
Expand Down

0 comments on commit bf0bfae

Please sign in to comment.