Rewrote the /ban add sub command
/ban add now replaces add, addtemp, and addip. New syntax: /ban add <target> [time] [reason] Examples: - /ban add Shank 10d Rewrote the ban system. - /ban add Ash - /ban add 127.0.0.1 5d Go work on homework. Note that if you want to specify a reason and a permaban, you need to use 0 (zero) as the duration. Examples: - /ban add Ash 0 Love ya. - /ban add Shank 0 Hacking. Closes #1510
This commit is contained in:
parent
51154c9bc9
commit
9dee0aee7d
1 changed files with 171 additions and 170 deletions
|
|
@ -35,6 +35,7 @@ using Terraria.GameContent.Events;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using OTAPI.Tile;
|
using OTAPI.Tile;
|
||||||
using TShockAPI.Localization;
|
using TShockAPI.Localization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace TShockAPI
|
namespace TShockAPI
|
||||||
{
|
{
|
||||||
|
|
@ -1273,200 +1274,202 @@ namespace TShockAPI
|
||||||
switch (subcmd)
|
switch (subcmd)
|
||||||
{
|
{
|
||||||
case "add":
|
case "add":
|
||||||
#region Add ban
|
#region Add Ban
|
||||||
{
|
{
|
||||||
if (args.Parameters.Count < 2)
|
if (args.Parameters.Count < 2)
|
||||||
{
|
{
|
||||||
args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}ban add <player> [reason]", Specifier);
|
args.Player.SendErrorMessage("Invalid command. Format: {0}ban add <player> [time] [reason]", Specifier);
|
||||||
|
args.Player.SendErrorMessage("Example: {0}ban add Shank 10d Hacking and cheating", Specifier);
|
||||||
|
args.Player.SendErrorMessage("Example: {0}ban add Ash", Specifier);
|
||||||
|
args.Player.SendErrorMessage("Use the time 0 (zero) for a permanent ban.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used only to notify if a ban was successful and who the ban was about
|
||||||
|
bool success = false;
|
||||||
|
string targetGeneralizedName = "";
|
||||||
|
|
||||||
|
// What if caller is console? Name?
|
||||||
|
|
||||||
|
// Effective ban target assignment
|
||||||
List<TSPlayer> players = TShock.Utils.FindPlayer(args.Parameters[1]);
|
List<TSPlayer> players = TShock.Utils.FindPlayer(args.Parameters[1]);
|
||||||
string reason = args.Parameters.Count > 2 ? String.Join(" ", args.Parameters.Skip(2)) : "Misbehavior.";
|
User offlineUser = TShock.Users.GetUserByName(args.Parameters[1]);
|
||||||
if (players.Count == 0)
|
|
||||||
|
// Determines if the caller is effective root for overriding permissions
|
||||||
|
bool callerIsEffectiveRoot = false;
|
||||||
|
|
||||||
|
// A ban source is effective root if they are not not real and not rest
|
||||||
|
// Super admins ingame who attempt to run this will have to remove
|
||||||
|
// the immune to ban permission if they want to ban an immune player
|
||||||
|
if (!(args.Player is TSRestPlayer) && !args.Player.RealPlayer)
|
||||||
{
|
{
|
||||||
var user = TShock.Users.GetUserByName(args.Parameters[1]);
|
callerIsEffectiveRoot = true;
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
bool force = !args.Player.RealPlayer;
|
|
||||||
|
|
||||||
if (user.Name == args.Player.Name && !force)
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("You can't ban yourself!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TShock.Groups.GetGroupByName(user.Group).HasPermission(Permissions.immunetoban) && !force)
|
|
||||||
args.Player.SendErrorMessage("You can't ban {0}!", user.Name);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (user.KnownIps == null)
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("Cannot ban {0} because they have no IPs to ban.", user.Name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var knownIps = JsonConvert.DeserializeObject<List<string>>(user.KnownIps);
|
|
||||||
TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.User.Name);
|
|
||||||
if (String.IsNullOrWhiteSpace(args.Player.User.Name))
|
|
||||||
{
|
|
||||||
if (args.Silent)
|
|
||||||
{
|
|
||||||
args.Player.SendInfoMessage("{0} was {1}banned for '{2}'.", user.Name, force ? "Force " : "", reason);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TSPlayer.All.SendInfoMessage("{0} was {1}banned for '{2}'.", user.Name, force ? "Force " : "", reason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (args.Silent)
|
|
||||||
{
|
|
||||||
args.Player.SendInfoMessage("{0}banned {1} for '{2}'.", force ? "Force " : "", user.Name, reason);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TSPlayer.All.SendInfoMessage("{0} {1}banned {2} for '{3}'.", args.Player.Name, force ? "Force " : "", user.Name, reason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
args.Player.SendErrorMessage("Invalid player or account!");
|
|
||||||
}
|
}
|
||||||
else if (players.Count > 1)
|
|
||||||
|
// The ban reason the ban is going to have
|
||||||
|
string banReason = "Unknown.";
|
||||||
|
|
||||||
|
// The default ban length
|
||||||
|
// 0 is permanent ban, otherwise temp ban
|
||||||
|
int banLengthInSeconds = 0;
|
||||||
|
|
||||||
|
// Figure out if param 2 is a time or 0 or garbage
|
||||||
|
if (args.Parameters.Count >= 3)
|
||||||
|
{
|
||||||
|
bool parsedOkay = false;
|
||||||
|
if (!(args.Parameters[2] == "0"))
|
||||||
|
{
|
||||||
|
parsedOkay = TShock.Utils.TryParseTime(args.Parameters[2], out banLengthInSeconds);
|
||||||
|
} else {
|
||||||
|
parsedOkay = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsedOkay)
|
||||||
|
{
|
||||||
|
args.Player.SendErrorMessage("Invalid time format. Example: 10d+5h+3m-2s.");
|
||||||
|
args.Player.SendErrorMessage("Use 0 (zero) for a permanent ban.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a reason exists, use the given reason.
|
||||||
|
if (args.Parameters.Count > 3)
|
||||||
|
{
|
||||||
|
banReason = String.Join(" ", args.Parameters.Skip(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad case: Players contains more than 1 person so we can't ban them
|
||||||
|
if (players.Count > 1)
|
||||||
|
{
|
||||||
TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
|
TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!TShock.Utils.Ban(players[0], reason, !args.Player.RealPlayer, args.Player.User.Name))
|
|
||||||
args.Player.SendErrorMessage("You can't ban {0}!", players[0].Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
return;
|
|
||||||
case "addip":
|
|
||||||
#region Add IP ban
|
|
||||||
{
|
|
||||||
if (args.Parameters.Count < 2)
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}ban addip <ip> [reason]", Specifier);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string ip = args.Parameters[1];
|
// Good case: Online ban for matching character.
|
||||||
string reason = args.Parameters.Count > 2
|
if (players.Count == 1)
|
||||||
? String.Join(" ", args.Parameters.GetRange(2, args.Parameters.Count - 2))
|
|
||||||
: "Manually added IP address ban.";
|
|
||||||
TShock.Bans.AddBan(ip, "", "", reason, false, args.Player.User.Name);
|
|
||||||
args.Player.SendSuccessMessage("Banned IP {0}.", ip);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
return;
|
|
||||||
case "addtemp":
|
|
||||||
#region Add temp ban
|
|
||||||
{
|
|
||||||
if (args.Parameters.Count < 3)
|
|
||||||
{
|
{
|
||||||
args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}ban addtemp <player> <time> [reason]", Specifier);
|
TSPlayer target = players[0];
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int time;
|
if (target.HasPermission(Permissions.immunetoban) && !callerIsEffectiveRoot)
|
||||||
if (!TShock.Utils.TryParseTime(args.Parameters[2], out time))
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("Invalid time string! Proper format: _d_h_m_s, with at least one time specifier.");
|
|
||||||
args.Player.SendErrorMessage("For example, 1d and 10h-30m+2m are both valid time strings, but 2 is not.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string reason = args.Parameters.Count > 3
|
|
||||||
? String.Join(" ", args.Parameters.Skip(3))
|
|
||||||
: "Misbehavior.";
|
|
||||||
|
|
||||||
List<TSPlayer> players = TShock.Utils.FindPlayer(args.Parameters[1]);
|
|
||||||
if (players.Count == 0)
|
|
||||||
{
|
|
||||||
var user = TShock.Users.GetUserByName(args.Parameters[1]);
|
|
||||||
if (user != null)
|
|
||||||
{
|
{
|
||||||
bool force = !args.Player.RealPlayer;
|
args.Player.SendErrorMessage("Permission denied. Target {0} is immune to ban.", target.Name);
|
||||||
if (TShock.Groups.GetGroupByName(user.Group).HasPermission(Permissions.immunetoban) && !force)
|
|
||||||
args.Player.SendErrorMessage("You can't ban {0}!", user.Name);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var knownIps = JsonConvert.DeserializeObject<List<string>>(user.KnownIps);
|
|
||||||
TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.User.Name, DateTime.UtcNow.AddSeconds(time).ToString("s"));
|
|
||||||
if (String.IsNullOrWhiteSpace(args.Player.User.Name))
|
|
||||||
{
|
|
||||||
if (args.Silent)
|
|
||||||
{
|
|
||||||
args.Player.SendInfoMessage("{0} was {1}banned for '{2}'.", user.Name, force ? "force " : "", reason);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TSPlayer.All.SendInfoMessage("{0} was {1}banned for '{2}'.", user.Name, force ? "force " : "", reason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (args.Silent)
|
|
||||||
{
|
|
||||||
args.Player.SendInfoMessage("{0} was {1}banned for '{2}'.", user.Name, force ? "force " : "", reason);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TSPlayer.All.SendInfoMessage("{0} {1}banned {2} for '{3}'.", args.Player.Name, force ? "force " : "", user.Name, reason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("Invalid player or account!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (players.Count > 1)
|
|
||||||
TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (args.Player.RealPlayer && players[0].HasPermission(Permissions.immunetoban))
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("You can't ban {0}!", players[0].Name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TShock.Bans.AddBan(players[0].IP, players[0].Name, players[0].UUID, reason,
|
targetGeneralizedName = target.Name;
|
||||||
false, args.Player.Name, DateTime.UtcNow.AddSeconds(time).ToString("s")))
|
success = TShock.Bans.AddBan(target.IP, target.Name, target.UUID, banReason, false, args.Player.User.Name,
|
||||||
|
banLengthInSeconds == 0 ? "" : banLengthInSeconds.ToString());
|
||||||
|
|
||||||
|
// Since this is an online ban, we need to dc the player and tell them now.
|
||||||
|
if (success)
|
||||||
{
|
{
|
||||||
players[0].Disconnect(String.Format("Banned: {0}", reason));
|
if (banLengthInSeconds == 0)
|
||||||
string verb = args.Player.RealPlayer ? "Force " : "";
|
{
|
||||||
if (args.Player.RealPlayer)
|
target.Disconnect(String.Format("Permanently banned for {0}", banReason));
|
||||||
if (args.Silent)
|
}
|
||||||
{
|
|
||||||
args.Player.SendSuccessMessage("{0}banned {1} for '{2}'", verb, players[0].Name, reason);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TSPlayer.All.SendSuccessMessage("{0} {1}banned {2} for '{3}'", args.Player.Name, verb, players[0].Name, reason);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (args.Silent)
|
target.Disconnect(String.Format("Banned for {0} seconds for {1}", banLengthInSeconds, banReason));
|
||||||
{
|
|
||||||
args.Player.SendSuccessMessage("{0}banned {1} for '{2}'", verb, players[0].Name, reason);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TSPlayer.All.SendSuccessMessage("{0} was {1}banned for '{2}'", players[0].Name, verb, reason);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
args.Player.SendErrorMessage("Failed to ban {0}, check logs.", players[0].Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Case: Players & user are invalid, could be IP?
|
||||||
|
// Note: Order matters. If this method is above the online player check,
|
||||||
|
// This enables you to ban an IP even if the player exists in the database as a player.
|
||||||
|
// You'll get two bans for the price of one, in theory, because both IP and user named IP will be banned.
|
||||||
|
// ??? edge cases are weird, but this is going to happen
|
||||||
|
// The only way around this is to either segregate off the IP code or do something else.
|
||||||
|
if (players.Count == 0)
|
||||||
|
{
|
||||||
|
// If the target is a valid IP...
|
||||||
|
string pattern = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
|
||||||
|
Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
|
||||||
|
if (r.IsMatch(args.Parameters[1])) {
|
||||||
|
targetGeneralizedName = String.Join(" ", "IP:", args.Parameters[1]);
|
||||||
|
success = TShock.Bans.AddBan(args.Parameters[1], "", "", banReason,
|
||||||
|
false, args.Player.User.Name, banLengthInSeconds == 0 ? "" : banLengthInSeconds.ToString());
|
||||||
|
if (success && offlineUser != null)
|
||||||
|
{
|
||||||
|
args.Player.SendSuccessMessage("Target IP {0} was banned successfully.", targetGeneralizedName);
|
||||||
|
args.Player.SendErrorMessage("Note: An account named with this IP address also exists.");
|
||||||
|
args.Player.SendErrorMessage("Note: It will also be banned.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Apparently there is no way to not IP ban someone
|
||||||
|
// This means that where we would normally just ban a "character name" here
|
||||||
|
// We can't because it requires some IP as a primary key.
|
||||||
|
if (offlineUser == null)
|
||||||
|
{
|
||||||
|
args.Player.SendErrorMessage("Unable to ban target {0}.", args.Parameters[1]);
|
||||||
|
args.Player.SendErrorMessage("Target is not a valid IP address, a valid online player, or a known offline user.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case: Offline ban
|
||||||
|
if (players.Count == 0 && offlineUser != null)
|
||||||
|
{
|
||||||
|
// Catch: we don't know an offline player's last login character name
|
||||||
|
// This means that we're banning their *user name* on the assumption that
|
||||||
|
// user name == character name
|
||||||
|
// (which may not be true)
|
||||||
|
// This needs to be fixed in a future implementation.
|
||||||
|
targetGeneralizedName = offlineUser.Name;
|
||||||
|
|
||||||
|
if (TShock.Groups.GetGroupByName(offlineUser.Group).HasPermission(Permissions.immunetoban) &&
|
||||||
|
!callerIsEffectiveRoot)
|
||||||
|
{
|
||||||
|
args.Player.SendErrorMessage("Permission denied. Target {0} is immune to ban.", targetGeneralizedName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offlineUser.KnownIps == null)
|
||||||
|
{
|
||||||
|
args.Player.SendErrorMessage("Unable to ban target {0} because they have no valid IP to ban.", targetGeneralizedName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string lastIP = JsonConvert.DeserializeObject<List<string>>(offlineUser.KnownIps).Last();
|
||||||
|
|
||||||
|
success =
|
||||||
|
TShock.Bans.AddBan(lastIP,
|
||||||
|
offlineUser.Name, offlineUser.UUID, banReason, false, args.Player.User.Name,
|
||||||
|
banLengthInSeconds == 0 ? "" : banLengthInSeconds.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
args.Player.SendSuccessMessage("{0} was successfully banned.", targetGeneralizedName);
|
||||||
|
args.Player.SendInfoMessage("Length: {0}", banLengthInSeconds == 0 ? "Permanent." : banLengthInSeconds + " seconds.");
|
||||||
|
args.Player.SendInfoMessage("Reason: {0}", banReason);
|
||||||
|
if (!args.Silent)
|
||||||
|
{
|
||||||
|
if (banLengthInSeconds == 0)
|
||||||
|
{
|
||||||
|
TSPlayer.All.SendErrorMessage("{0} was permanently banned by {1} for: {2}",
|
||||||
|
targetGeneralizedName, args.Player.User.Name, banReason);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TSPlayer.All.SendErrorMessage("{0} was temp banned for {1} seconds by {2} for: {3}",
|
||||||
|
targetGeneralizedName, banLengthInSeconds, args.Player.User.Name, banReason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.Player.SendErrorMessage("{0} was NOT banned due to a database error or other system problem.", targetGeneralizedName);
|
||||||
|
args.Player.SendErrorMessage("If this player is online, they have NOT been kicked.");
|
||||||
|
args.Player.SendErrorMessage("Check the system logs for details.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
return;
|
|
||||||
case "del":
|
case "del":
|
||||||
#region Delete ban
|
#region Delete ban
|
||||||
{
|
{
|
||||||
|
|
@ -1522,9 +1525,7 @@ namespace TShockAPI
|
||||||
|
|
||||||
var lines = new List<string>
|
var lines = new List<string>
|
||||||
{
|
{
|
||||||
"add <player> [reason] - Bans a player or user account if the player is not online.",
|
"add <target> <time> [reason] - Bans a player or user account if the player is not online.",
|
||||||
"addip <ip> [reason] - Bans an IP.",
|
|
||||||
"addtemp <player> <time> [reason] - Temporarily bans a player.",
|
|
||||||
"del <player> - Unbans a player.",
|
"del <player> - Unbans a player.",
|
||||||
"delip <ip> - Unbans an IP.",
|
"delip <ip> - Unbans an IP.",
|
||||||
"list [page] - Lists all player bans.",
|
"list [page] - Lists all player bans.",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue