Ban rewrite
This commit is contained in:
parent
5af1f8f76a
commit
56de9f6684
9 changed files with 679 additions and 860 deletions
|
|
@ -1267,328 +1267,271 @@ namespace TShockAPI
|
||||||
|
|
||||||
private static void Ban(CommandArgs args)
|
private static void Ban(CommandArgs args)
|
||||||
{
|
{
|
||||||
|
//Ban syntax:
|
||||||
|
// ban add <target> [reason] [duration] [flags (default: -a -u -ip)]
|
||||||
|
// Valid flags: -a (ban account name), -u (ban UUID), -n (ban character name), -ip (ban IP address), -e (exact, ban the identifier provided as 'target')
|
||||||
|
// Unless -e is passed to the command, <target> is assumed to be a player or player index.
|
||||||
|
// ban del <target>
|
||||||
|
// Target is expected to be an identifier in the format 'identifier_prefix:identifier'. Eg acc:MyAccountName
|
||||||
|
// ban list [page]
|
||||||
|
// Displays a paginated list of bans
|
||||||
|
// ban details <target>
|
||||||
|
// Target is expected to be an identifier in the format 'identifier_prefix:identifier'. Eg acc:MyAccountName
|
||||||
|
// Output: Banned Identifier - expiration
|
||||||
|
// Reason: text
|
||||||
|
// Banned by: name
|
||||||
|
|
||||||
|
void Help()
|
||||||
|
{
|
||||||
|
if (args.Parameters.Count > 1)
|
||||||
|
{
|
||||||
|
MoreHelp(args.Parameters[1].ToLower());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Player.SendMessage("TShock Ban Help", Color.White);
|
||||||
|
args.Player.SendMessage("Available Ban commands:", Color.White);
|
||||||
|
args.Player.SendMessage("ban [c/FFAAAA:add] <target> [flags]", Color.White);
|
||||||
|
args.Player.SendMessage("ban [c/FFAAAA:del] <target>", Color.White);
|
||||||
|
args.Player.SendMessage("ban [c/FFAAAA:list]", Color.White);
|
||||||
|
args.Player.SendMessage("ban [c/FFAAAA:details] <target>", Color.White);
|
||||||
|
args.Player.SendMessage("For more info, use [c/AAAAFF:ban help] [c/FFAAAA:command]", Color.White);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreHelp(string cmd)
|
||||||
|
{
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case "add":
|
||||||
|
args.Player.SendMessage("", Color.White);
|
||||||
|
args.Player.SendMessage("Ban Add Syntax", Color.White);
|
||||||
|
args.Player.SendMessage("[c/AAAAFF:ban add] [c/FFAAAA:<target>] [[c/AAAAFF:reason]] [[c/FFAAFF:duration]] [[c/AAFFAA:flags]]", Color.White);
|
||||||
|
args.Player.SendMessage("- [c/FFAAFF:Duration]: uses the format [c/FFAAFF:0d0m0s] to determine the length of the ban. Eg a value of [c/FFAAFF:10d30m0s] would represent 10 days, 30 minutes, 0 seconds.", Color.White);
|
||||||
|
args.Player.SendMessage("- [c/AAFFAA:flags]: -a (account name), -u (UUID), -n (character name), -ip (IP address), -e (exact, [c/FFAAAA:target] will be treated as identifier)", Color.White);
|
||||||
|
args.Player.SendMessage(" Unless [c/AAFFAA:-e] is passed to the command, [c/FFAAAA:target] is assumed to be a player or player index", Color.White);
|
||||||
|
args.Player.SendMessage(" If no [c/AAFFAA:flags] are specified, the command uses [c/AAFFAA:-a -u -ip] by default.", Color.White);
|
||||||
|
args.Player.SendMessage("Example usage: [c/AAAAFF:ban add] [c/FFAAAA:ExamplePlayer] [c/AAAAFF:\"Cheating\"] 10d30m0s [c/AAFFAA:-a -u -ip]", Color.White);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "del":
|
||||||
|
args.Player.SendMessage("", Color.White);
|
||||||
|
args.Player.SendMessage("Ban Del Syntax", Color.White);
|
||||||
|
args.Player.SendMessage("[c/AAAAFF:ban del] [c/FFAAAA:target]", Color.White);
|
||||||
|
args.Player.SendMessage("- [c/FFAAAA:Target] is expected to be an identifier in the format 'identifier_prefix:identifier'. Eg [c/FFAAAA:acc:MyAccountName]", Color.White);
|
||||||
|
args.Player.SendMessage("Example usage: [c/AAAAFF:ban del] [c/FFAAAA:acc:ExampleAccount]", Color.White);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "list":
|
||||||
|
args.Player.SendMessage("", Color.White);
|
||||||
|
args.Player.SendMessage("Ban List Syntax", Color.White);
|
||||||
|
args.Player.SendMessage("[c/AAAAFF:ban list] [[c/FFAAFF:page]]", Color.White);
|
||||||
|
args.Player.SendMessage("- Lists active bans. Color trends towards green as the ban approaches expiration", Color.White);
|
||||||
|
args.Player.SendMessage("Example usage: [c/AAAAFF:ban list]", Color.White);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "details":
|
||||||
|
args.Player.SendMessage("", Color.White);
|
||||||
|
args.Player.SendMessage("Ban Details Syntax", Color.White);
|
||||||
|
args.Player.SendMessage("[c/AAAAFF:ban details] [c/FFAAAA:target]", Color.White);
|
||||||
|
args.Player.SendMessage("- [c/FFAAAA:Target] is expected to be an identifier in the format 'identifier_prefix:identifier'. Eg [c/FFAAAA:acc:MyAccountName]", Color.White);
|
||||||
|
args.Player.SendMessage("Example usage: [c/AAAAFF:ban details] [c/FFAAAA:acc:ExampleAccount]", Color.White);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
args.Player.SendMessage("Unknown ban command. Try 'add', 'del', 'list', or 'details'", Color.White);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddBan()
|
||||||
|
{
|
||||||
|
if (!args.Parameters.TryGetValue(1, out string target))
|
||||||
|
{
|
||||||
|
args.Player.SendMessage("Invalid Ban Add syntax. Refer to [c/AAAAFF:ban help add] for details on how to use the [c/AAAAFF:ban add] command", Color.White);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exactTarget = args.Parameters.Any(p => p == "-e");
|
||||||
|
bool banAccount = args.Parameters.Any(p => p == "-a");
|
||||||
|
bool banUuid = args.Parameters.Any(p => p == "-u");
|
||||||
|
bool banName = args.Parameters.Any(p => p == "-n");
|
||||||
|
bool banIp = args.Parameters.Any(p => p == "-ip");
|
||||||
|
|
||||||
|
args.Parameters.TryGetValue(2, out string reason);
|
||||||
|
args.Parameters.TryGetValue(3, out string duration);
|
||||||
|
DateTime expiration = DateTime.MaxValue;
|
||||||
|
|
||||||
|
if (TShock.Utils.TryParseTime(duration, out int seconds))
|
||||||
|
{
|
||||||
|
expiration = DateTime.UtcNow.AddSeconds(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
//If no flags were specified, default to account, uuid, and IP
|
||||||
|
if (!exactTarget && !banAccount && !banUuid && !banName && !banIp)
|
||||||
|
{
|
||||||
|
banAccount = banUuid = banIp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exactTarget)
|
||||||
|
{
|
||||||
|
if (TShock.Bans.InsertBan(target, reason ?? "Banned", args.Player.Account.Name, DateTime.UtcNow, expiration) != null)
|
||||||
|
{
|
||||||
|
args.Player.SendSuccessMessage("Ban added.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.Player.SendErrorMessage("Failed to insert ban. Ban may already exist, or an error occured.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var players = TSPlayer.FindByNameOrID(target);
|
||||||
|
|
||||||
|
if (players.Count > 1)
|
||||||
|
{
|
||||||
|
args.Player.SendMultipleMatchError(players.Select(p => p.Name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (players.Count < 1)
|
||||||
|
{
|
||||||
|
args.Player.SendErrorMessage("Could not find the target specified. Check that you have the correct spelling.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var player = players[0];
|
||||||
|
var identifiers = new List<string>();
|
||||||
|
string identifier;
|
||||||
|
|
||||||
|
if (banAccount)
|
||||||
|
{
|
||||||
|
if (player.Account != null)
|
||||||
|
{
|
||||||
|
identifier = $"{DB.Ban.Identifiers.Account}{player.Account.Name}";
|
||||||
|
if (TShock.Bans.InsertBan(identifier, reason, args.Player.Account.Name, DateTime.UtcNow, expiration) != null)
|
||||||
|
{
|
||||||
|
identifiers.Add(identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (banUuid)
|
||||||
|
{
|
||||||
|
identifier = $"{DB.Ban.Identifiers.UUID}{player.UUID}";
|
||||||
|
if (TShock.Bans.InsertBan($"{DB.Ban.Identifiers.UUID}{player.UUID}", reason, args.Player.Account.Name, DateTime.UtcNow, expiration) != null)
|
||||||
|
{
|
||||||
|
identifiers.Add(identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (banName)
|
||||||
|
{
|
||||||
|
identifier = $"{DB.Ban.Identifiers.Name}{player.Name}";
|
||||||
|
if (TShock.Bans.InsertBan($"{DB.Ban.Identifiers.Name}{player.Name}", reason, args.Player.Account.Name, DateTime.UtcNow, expiration) != null)
|
||||||
|
{
|
||||||
|
identifiers.Add(identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (banIp)
|
||||||
|
{
|
||||||
|
identifier = $"{DB.Ban.Identifiers.IP}{player.IP}";
|
||||||
|
if (TShock.Bans.InsertBan($"{DB.Ban.Identifiers.IP}{player.IP}", reason, args.Player.Account.Name, DateTime.UtcNow, expiration) != null)
|
||||||
|
{
|
||||||
|
identifiers.Add(identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Player.SendSuccessMessage("Bans added for identifiers: ", string.Join(", ", identifiers));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DelBan()
|
||||||
|
{
|
||||||
|
if (!args.Parameters.TryGetValue(1, out string target))
|
||||||
|
{
|
||||||
|
args.Player.SendMessage("Invalid Ban Del syntax. Refer to [c/AAAAFF:ban help del] for details on how to use the [c/AAAAFF:ban del] command", Color.White);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TShock.Bans.RemoveBan(target))
|
||||||
|
{
|
||||||
|
args.Player.SendSuccessMessage("Ban removed.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.Player.SendErrorMessage("Failed to remove ban.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListBans()
|
||||||
|
{
|
||||||
|
int pageNumber;
|
||||||
|
if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
|
||||||
|
{
|
||||||
|
args.Player.SendMessage("Invalid Ban List syntax. Refer to [c/AAAAFF:ban help list] for details on how to use the [c/AAAAFF:ban list] command", Color.White);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Ban> bans = TShock.Bans.GetAllBans();
|
||||||
|
|
||||||
|
var nameBans = from ban in bans
|
||||||
|
select ban.Identifier;
|
||||||
|
|
||||||
|
PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(nameBans),
|
||||||
|
new PaginationTools.Settings
|
||||||
|
{
|
||||||
|
HeaderFormat = "Bans ({0}/{1}):",
|
||||||
|
FooterFormat = "Type {0}ban list {{0}} for more.".SFormat(Specifier),
|
||||||
|
NothingToDisplayString = "There are currently no bans."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void BanDetails()
|
||||||
|
{
|
||||||
|
if (!args.Parameters.TryGetValue(1, out string target))
|
||||||
|
{
|
||||||
|
args.Player.SendMessage("Invalid Ban Details syntax. Refer to [c/AAAAFF:ban help details] for details on how to use the [c/AAAAFF:ban details] command", Color.White);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ban ban = TShock.Bans.GetBanByIdentifier(target);
|
||||||
|
|
||||||
|
if (ban == null)
|
||||||
|
{
|
||||||
|
args.Player.SendErrorMessage("No ban found matching the given identifier");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Player.SendMessage($"{ban.Identifier}", Color.White);
|
||||||
|
args.Player.SendMessage($"Reason: {ban.Reason}", Color.White);
|
||||||
|
args.Player.SendMessage($"Banned by: [c/AAFFAA:{ban.BanningUser}] at [c/AAAAFF:time]", Color.White);
|
||||||
|
}
|
||||||
|
|
||||||
string subcmd = args.Parameters.Count == 0 ? "help" : args.Parameters[0].ToLower();
|
string subcmd = args.Parameters.Count == 0 ? "help" : args.Parameters[0].ToLower();
|
||||||
switch (subcmd)
|
switch (subcmd)
|
||||||
{
|
{
|
||||||
case "add":
|
|
||||||
#region Add Ban
|
|
||||||
{
|
|
||||||
if (args.Parameters.Count < 2)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used only to notify if a ban was successful and who the ban was about
|
|
||||||
bool success = false;
|
|
||||||
string targetGeneralizedName = "";
|
|
||||||
|
|
||||||
// Effective ban target assignment
|
|
||||||
List<TSPlayer> players = TSPlayer.FindByNameOrID(args.Parameters[1]);
|
|
||||||
|
|
||||||
// Bad case: Players contains more than 1 person so we can't ban them
|
|
||||||
if (players.Count > 1)
|
|
||||||
{
|
|
||||||
//Fail fast
|
|
||||||
args.Player.SendMultipleMatchError(players.Select(p => p.Name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserAccount offlineUserAccount = TShock.UserAccounts.GetUserAccountByName(args.Parameters[1]);
|
|
||||||
|
|
||||||
// Storage variable to determine if the command executor is the server console
|
|
||||||
// If it is, we assume they have full control and let them override permission checks
|
|
||||||
bool callerIsServerConsole = args.Player is TSServerPlayer;
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Good case: Online ban for matching character.
|
|
||||||
if (players.Count == 1)
|
|
||||||
{
|
|
||||||
TSPlayer target = players[0];
|
|
||||||
|
|
||||||
if (target.HasPermission(Permissions.immunetoban) && !callerIsServerConsole)
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("Permission denied. Target {0} is immune to ban.", target.Name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
targetGeneralizedName = target.Name;
|
|
||||||
success = TShock.Bans.AddBan(target.IP, target.Name, target.UUID, target.Account?.Name ?? "", banReason, false, args.Player.Account.Name,
|
|
||||||
banLengthInSeconds == 0 ? "" : DateTime.UtcNow.AddSeconds(banLengthInSeconds).ToString("s"));
|
|
||||||
|
|
||||||
// Since this is an online ban, we need to dc the player and tell them now.
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
if (banLengthInSeconds == 0)
|
|
||||||
{
|
|
||||||
target.Disconnect(String.Format("Permanently banned for {0}", banReason));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
target.Disconnect(String.Format("Banned for {0} seconds for {1}", banLengthInSeconds, banReason));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 = "IP: " + args.Parameters[1];
|
|
||||||
success = TShock.Bans.AddBan(args.Parameters[1], "", "", "", banReason,
|
|
||||||
false, args.Player.Account.Name, banLengthInSeconds == 0 ? "" : DateTime.UtcNow.AddSeconds(banLengthInSeconds).ToString("s"));
|
|
||||||
if (success && offlineUserAccount != 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 (offlineUserAccount == 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 && offlineUserAccount != 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 = offlineUserAccount.Name;
|
|
||||||
|
|
||||||
if (TShock.Groups.GetGroupByName(offlineUserAccount.Group).HasPermission(Permissions.immunetoban) &&
|
|
||||||
!callerIsServerConsole)
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("Permission denied. Target {0} is immune to ban.", targetGeneralizedName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offlineUserAccount.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>>(offlineUserAccount.KnownIps).Last();
|
|
||||||
|
|
||||||
success =
|
|
||||||
TShock.Bans.AddBan(lastIP,
|
|
||||||
"", offlineUserAccount.UUID, offlineUserAccount.Name, banReason, false, args.Player.Account.Name,
|
|
||||||
banLengthInSeconds == 0 ? "" : DateTime.UtcNow.AddSeconds(banLengthInSeconds).ToString("s"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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.Account.Name, banReason);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TSPlayer.All.SendErrorMessage("{0} was temp banned for {1} seconds by {2} for: {3}",
|
|
||||||
targetGeneralizedName, banLengthInSeconds, args.Player.Account.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
|
|
||||||
case "del":
|
|
||||||
#region Delete ban
|
|
||||||
{
|
|
||||||
if (args.Parameters.Count != 2)
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}ban del <player>", Specifier);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string plStr = args.Parameters[1];
|
|
||||||
Ban ban = TShock.Bans.GetBanByName(plStr, false);
|
|
||||||
if (ban != null)
|
|
||||||
{
|
|
||||||
if (TShock.Bans.RemoveBan(ban.Name, true))
|
|
||||||
args.Player.SendSuccessMessage("Unbanned {0} ({1}).", ban.Name, ban.IP);
|
|
||||||
else
|
|
||||||
args.Player.SendErrorMessage("Failed to unban {0} ({1}), check logs.", ban.Name, ban.IP);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
args.Player.SendErrorMessage("No bans for {0} exist.", plStr);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
return;
|
|
||||||
case "delip":
|
|
||||||
#region Delete IP ban
|
|
||||||
{
|
|
||||||
if (args.Parameters.Count != 2)
|
|
||||||
{
|
|
||||||
args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}ban delip <ip>", Specifier);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string ip = args.Parameters[1];
|
|
||||||
Ban ban = TShock.Bans.GetBanByIp(ip);
|
|
||||||
if (ban != null)
|
|
||||||
{
|
|
||||||
if (TShock.Bans.RemoveBan(ban.IP, false))
|
|
||||||
args.Player.SendSuccessMessage("Unbanned IP {0} ({1}).", ban.IP, ban.Name);
|
|
||||||
else
|
|
||||||
args.Player.SendErrorMessage("Failed to unban IP {0} ({1}), check logs.", ban.IP, ban.Name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
args.Player.SendErrorMessage("IP {0} is not banned.", ip);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
return;
|
|
||||||
case "help":
|
case "help":
|
||||||
#region Help
|
Help();
|
||||||
{
|
break;
|
||||||
int pageNumber;
|
|
||||||
if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var lines = new List<string>
|
case "add":
|
||||||
{
|
AddBan();
|
||||||
"add <target> <time> [reason] - Bans a player or user account if the player is not online.",
|
break;
|
||||||
"del <player> - Unbans a player.",
|
|
||||||
"delip <ip> - Unbans an IP.",
|
case "del":
|
||||||
"list [page] - Lists all player bans.",
|
DelBan();
|
||||||
"listip [page] - Lists all IP bans."
|
break;
|
||||||
};
|
|
||||||
|
|
||||||
PaginationTools.SendPage(args.Player, pageNumber, lines,
|
|
||||||
new PaginationTools.Settings
|
|
||||||
{
|
|
||||||
HeaderFormat = "Ban Sub-Commands ({0}/{1}):",
|
|
||||||
FooterFormat = "Type {0}ban help {{0}} for more sub-commands.".SFormat(Specifier)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
return;
|
|
||||||
case "list":
|
case "list":
|
||||||
#region List bans
|
ListBans();
|
||||||
{
|
break;
|
||||||
int pageNumber;
|
|
||||||
if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Ban> bans = TShock.Bans.GetBans();
|
case "details":
|
||||||
|
BanDetails();
|
||||||
|
break;
|
||||||
|
|
||||||
var nameBans = from ban in bans
|
|
||||||
where !String.IsNullOrEmpty(ban.Name)
|
|
||||||
select ban.Name;
|
|
||||||
|
|
||||||
PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(nameBans),
|
|
||||||
new PaginationTools.Settings
|
|
||||||
{
|
|
||||||
HeaderFormat = "Bans ({0}/{1}):",
|
|
||||||
FooterFormat = "Type {0}ban list {{0}} for more.".SFormat(Specifier),
|
|
||||||
NothingToDisplayString = "There are currently no bans."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
return;
|
|
||||||
case "listip":
|
|
||||||
#region List IP bans
|
|
||||||
{
|
|
||||||
int pageNumber;
|
|
||||||
if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Ban> bans = TShock.Bans.GetBans();
|
|
||||||
|
|
||||||
var ipBans = from ban in bans
|
|
||||||
where String.IsNullOrEmpty(ban.Name)
|
|
||||||
select ban.IP;
|
|
||||||
|
|
||||||
PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(ipBans),
|
|
||||||
new PaginationTools.Settings
|
|
||||||
{
|
|
||||||
HeaderFormat = "IP Bans ({0}/{1}):",
|
|
||||||
FooterFormat = "Type {0}ban listip {{0}} for more.".SFormat(Specifier),
|
|
||||||
NothingToDisplayString = "There are currently no IP bans."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
return;
|
|
||||||
default:
|
default:
|
||||||
args.Player.SendErrorMessage("Invalid subcommand! Type {0}ban help for more information.", Specifier);
|
break;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,15 @@ namespace TShockAPI.DB
|
||||||
{
|
{
|
||||||
private IDbConnection database;
|
private IDbConnection database;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event invoked when a ban check occurs
|
||||||
|
/// </summary>
|
||||||
|
public static event EventHandler<BanEventArgs> OnBanCheck;
|
||||||
|
/// <summary>
|
||||||
|
/// Event invoked when a ban is added
|
||||||
|
/// </summary>
|
||||||
|
public static event EventHandler<BanEventArgs> OnBanAdded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="TShockAPI.DB.BanManager"/> class.
|
/// Initializes a new instance of the <see cref="TShockAPI.DB.BanManager"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -39,15 +48,12 @@ namespace TShockAPI.DB
|
||||||
{
|
{
|
||||||
database = db;
|
database = db;
|
||||||
|
|
||||||
var table = new SqlTable("Bans",
|
var table = new SqlTable("PlayerBans",
|
||||||
new SqlColumn("IP", MySqlDbType.String, 16) { Primary = true },
|
new SqlColumn("Identifier", MySqlDbType.Text) { Primary = true, Unique = true },
|
||||||
new SqlColumn("Name", MySqlDbType.Text),
|
|
||||||
new SqlColumn("UUID", MySqlDbType.Text),
|
|
||||||
new SqlColumn("Reason", MySqlDbType.Text),
|
new SqlColumn("Reason", MySqlDbType.Text),
|
||||||
new SqlColumn("BanningUser", MySqlDbType.Text),
|
new SqlColumn("BanningUser", MySqlDbType.Text),
|
||||||
new SqlColumn("Date", MySqlDbType.Text),
|
new SqlColumn("Date", MySqlDbType.Text),
|
||||||
new SqlColumn("Expiration", MySqlDbType.Text),
|
new SqlColumn("Expiration", MySqlDbType.Text)
|
||||||
new SqlColumn("AccountName", MySqlDbType.Text)
|
|
||||||
);
|
);
|
||||||
var creator = new SqlTableCreator(db,
|
var creator = new SqlTableCreator(db,
|
||||||
db.GetSqlType() == SqlType.Sqlite
|
db.GetSqlType() == SqlType.Sqlite
|
||||||
|
|
@ -62,55 +68,204 @@ namespace TShockAPI.DB
|
||||||
System.Console.WriteLine("Possible problem with your database - is Sqlite3.dll present?");
|
System.Console.WriteLine("Possible problem with your database - is Sqlite3.dll present?");
|
||||||
throw new Exception("Could not find a database library (probably Sqlite3.dll)");
|
throw new Exception("Could not find a database library (probably Sqlite3.dll)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnBanCheck += CheckBanValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a ban by IP.
|
/// Converts bans from the old ban system to the new.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ip">The IP.</param>
|
public void ConvertBans()
|
||||||
/// <returns>The ban.</returns>
|
|
||||||
public Ban GetBanByIp(string ip)
|
|
||||||
{
|
{
|
||||||
try
|
using (var reader = database.QueryReader("SELECT * FROM Bans"))
|
||||||
{
|
{
|
||||||
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE IP=@0", ip))
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
if (reader.Read())
|
var ip = reader.Get<string>("IP");
|
||||||
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("UUID"), reader.Get<string>("AccountName"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration"));
|
var uuid = reader.Get<string>("UUID");
|
||||||
|
var account = reader.Get<string>("AccountName");
|
||||||
|
var reason = reader.Get<string>("Reason");
|
||||||
|
var banningUser = reader.Get<string>("BanningUser");
|
||||||
|
var date = reader.Get<string>("Date");
|
||||||
|
var expiration = reader.Get<string>("Expiration");
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(ip))
|
||||||
|
{
|
||||||
|
InsertBan($"{Ban.Identifiers.IP}{ip}", reason, banningUser, date, expiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(account))
|
||||||
|
{
|
||||||
|
InsertBan($"{Ban.Identifiers.Account}{account}", reason, banningUser, date, expiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(uuid))
|
||||||
|
{
|
||||||
|
InsertBan($"{Ban.Identifiers.UUID}{uuid}", reason, banningUser, date, expiration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether or not a ban is valid
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ban"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool IsValidBan(Ban ban)
|
||||||
|
{
|
||||||
|
BanEventArgs args = new BanEventArgs { Ban = ban };
|
||||||
|
OnBanCheck?.Invoke(this, args);
|
||||||
|
|
||||||
|
return args.Valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void CheckBanValid(object sender, BanEventArgs args)
|
||||||
|
{
|
||||||
|
//We consider a ban to be valid if the start time is before now and the end time is after now
|
||||||
|
args.Valid = args.Ban.BanDateTime < DateTime.UtcNow && args.Ban.ExpirationDateTime > DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new ban for the given identifier. If the addition succeeds, returns a ban object with the ban details. Else returns null
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identifier"></param>
|
||||||
|
/// <param name="reason"></param>
|
||||||
|
/// <param name="banningUser"></param>
|
||||||
|
/// <param name="fromDate"></param>
|
||||||
|
/// <param name="toDate"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Ban InsertBan(string identifier, string reason, string banningUser, DateTime fromDate, DateTime toDate)
|
||||||
|
=> InsertBan(identifier, reason, banningUser, fromDate.ToString("s"), toDate.ToString("s"));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new ban for the given identifier. If the addition succeeds, returns a ban object with the ban details. Else returns null
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identifier"></param>
|
||||||
|
/// <param name="reason"></param>
|
||||||
|
/// <param name="banningUser"></param>
|
||||||
|
/// <param name="fromDate"></param>
|
||||||
|
/// <param name="toDate"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Ban InsertBan(string identifier, string reason, string banningUser, string fromDate, string toDate)
|
||||||
|
{
|
||||||
|
Ban b = new Ban(identifier, reason, banningUser, fromDate, toDate);
|
||||||
|
|
||||||
|
BanEventArgs args = new BanEventArgs { Ban = b };
|
||||||
|
|
||||||
|
OnBanAdded?.Invoke(this, args);
|
||||||
|
|
||||||
|
if (!args.Valid)
|
||||||
{
|
{
|
||||||
TShock.Log.Error(ex.ToString());
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rowsModified = database.Query("INSERT OR IGNORE INTO PlayerBans (Identifier, Reason, BanningUser, Date, Expiration) VALUES (@0, @1, @2, @3, @4);", identifier, reason, banningUser, fromDate, toDate);
|
||||||
|
//Return the ban if the query actually inserted the row. If the given identifier already exists, the INSERT is ignored and 0 rows are modified.
|
||||||
|
return rowsModified != 0 ? b : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to remove a ban. Returns true if the ban was removed or expired. False if the ban could not be removed or expired
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identifier"></param>
|
||||||
|
/// <param name="fullDelete">If true, deletes the ban from the database. If false, marks the expiration time as now, rendering the ban expired. Defaults to false</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool RemoveBan(string identifier, bool fullDelete = false)
|
||||||
|
{
|
||||||
|
int rowsModified;
|
||||||
|
if (fullDelete)
|
||||||
|
{
|
||||||
|
rowsModified = database.Query("DELETE FROM PlayerBans WHERE Identifier=@0", identifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rowsModified = database.Query("UPDATE PlayerBans SET Expiration=@0 WHERE Identifier=@1", DateTime.UtcNow.ToString("s"), identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rowsModified > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a ban for a given identifier, or null if no matches are found
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identifier"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Ban GetBanByIdentifier(string identifier)
|
||||||
|
{
|
||||||
|
using (var reader = database.QueryReader("SELECT * FROM PlayerBans WHERE Identifier=@0", identifier))
|
||||||
|
{
|
||||||
|
if (reader.Read())
|
||||||
|
{
|
||||||
|
var id = reader.Get<string>("Identifier");
|
||||||
|
var reason = reader.Get<string>("Reason");
|
||||||
|
var banningUser = reader.Get<string>("BanningUser");
|
||||||
|
var date = reader.Get<string>("Date");
|
||||||
|
var expiration = reader.Get<string>("Expiration");
|
||||||
|
|
||||||
|
return new Ban(id, reason, banningUser, date, expiration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves an enumerable of bans for a given set of identifiers
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identifiers"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IEnumerable<Ban> GetBansByIdentifiers(params string[] identifiers)
|
||||||
|
{
|
||||||
|
//Generate a sequence of '@0, @1, @2, ... etc'
|
||||||
|
var parameters = string.Join(", ", Enumerable.Range(0, identifiers.Count()).Select(p => $"@{p}"));
|
||||||
|
|
||||||
|
using (var reader = database.QueryReader($"SELECT * FROM PlayerBans WHERE Identifier IN ({parameters})", identifiers))
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
var id = reader.Get<string>("Identifier");
|
||||||
|
var reason = reader.Get<string>("Reason");
|
||||||
|
var banningUser = reader.Get<string>("BanningUser");
|
||||||
|
var date = reader.Get<string>("Date");
|
||||||
|
var expiration = reader.Get<string>("Expiration");
|
||||||
|
|
||||||
|
yield return new Ban(id, reason, banningUser, date, expiration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a list of bans sorted by their addition date from newest to oldest
|
/// Gets a list of bans sorted by their addition date from newest to oldest
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<Ban> GetBans() => GetSortedBans(BanSortMethod.AddedNewestToOldest).ToList();
|
public List<Ban> GetAllBans() => GetAllBansSorted(BanSortMethod.AddedNewestToOldest).ToList();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves an enumerable of <see cref="Ban"/> objects, sorted using the provided sort method
|
/// Retrieves an enumerable of <see cref="Ban"/> objects, sorted using the provided sort method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sortMethod"></param>
|
/// <param name="sortMethod"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IEnumerable<Ban> GetSortedBans(BanSortMethod sortMethod)
|
public IEnumerable<Ban> GetAllBansSorted(BanSortMethod sortMethod)
|
||||||
{
|
{
|
||||||
List<Ban> banlist = new List<Ban>();
|
List<Ban> banlist = new List<Ban>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var reader = database.QueryReader("SELECT * FROM Bans"))
|
var orderBy = SortToOrderByMap[sortMethod];
|
||||||
|
using (var reader = database.QueryReader($"SELECT * FROM PlayerBans ORDER BY {orderBy}"))
|
||||||
{
|
{
|
||||||
while (reader.Read())
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
banlist.Add(new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("UUID"), reader.Get<string>("AccountName"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration")));
|
var identifier = reader.Get<string>("Identifier");
|
||||||
}
|
var reason = reader.Get<string>("Reason");
|
||||||
|
var banningUser = reader.Get<string>("BanningUser");
|
||||||
|
var date = reader.Get<string>("Date");
|
||||||
|
var expiration = reader.Get<string>("Expiration");
|
||||||
|
|
||||||
banlist.Sort(new BanComparer(sortMethod));
|
var ban = new Ban(identifier, reason, banningUser, date, expiration);
|
||||||
return banlist;
|
banlist.Add(ban);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return banlist;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -121,172 +276,14 @@ namespace TShockAPI.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a ban by name.
|
/// Removes all bans from the database
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name.</param>
|
|
||||||
/// <param name="casesensitive">Whether to check with case sensitivity.</param>
|
|
||||||
/// <returns>The ban.</returns>
|
|
||||||
public Ban GetBanByName(string name, bool casesensitive = true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var namecol = casesensitive ? "Name" : "UPPER(Name)";
|
|
||||||
if (!casesensitive)
|
|
||||||
name = name.ToUpper();
|
|
||||||
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE " + namecol + "=@0", name))
|
|
||||||
{
|
|
||||||
if (reader.Read())
|
|
||||||
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("UUID"), reader.Get<string>("AccountName"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
TShock.Log.Error(ex.ToString());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a ban by account name (not player/character name).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name.</param>
|
|
||||||
/// <param name="casesensitive">Whether to check with case sensitivity.</param>
|
|
||||||
/// <returns>The ban.</returns>
|
|
||||||
public Ban GetBanByAccountName(string name, bool casesensitive = false)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var namecol = casesensitive ? "AccountName" : "UPPER(AccountName)";
|
|
||||||
if (!casesensitive)
|
|
||||||
name = name.ToUpper();
|
|
||||||
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE " + namecol + "=@0", name))
|
|
||||||
{
|
|
||||||
if (reader.Read())
|
|
||||||
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("UUID"), reader.Get<string>("AccountName"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
TShock.Log.Error(ex.ToString());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a ban by UUID.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="uuid">The UUID.</param>
|
|
||||||
/// <returns>The ban.</returns>
|
|
||||||
public Ban GetBanByUUID(string uuid)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE UUID=@0", uuid))
|
|
||||||
{
|
|
||||||
if (reader.Read())
|
|
||||||
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("UUID"), reader.Get<string>("AccountName"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
TShock.Log.Error(ex.ToString());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a ban.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns><c>true</c>, if ban was added, <c>false</c> otherwise.</returns>
|
|
||||||
/// <param name="ip">Ip.</param>
|
|
||||||
/// <param name="name">Name.</param>
|
|
||||||
/// <param name="uuid">UUID.</param>
|
|
||||||
/// <param name="reason">Reason.</param>
|
|
||||||
/// <param name="exceptions">If set to <c>true</c> enable throwing exceptions.</param>
|
|
||||||
/// <param name="banner">Banner.</param>
|
|
||||||
/// <param name="expiration">Expiration date.</param>
|
|
||||||
public bool AddBan(string ip, string name = "", string uuid = "", string accountName = "", string reason = "", bool exceptions = false, string banner = "", string expiration = "")
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If the ban already exists, update its entry with the new date
|
|
||||||
* and expiration details.
|
|
||||||
*/
|
|
||||||
if (GetBanByIp(ip) != null)
|
|
||||||
{
|
|
||||||
return database.Query("UPDATE Bans SET Date = @0, Expiration = @1 WHERE IP = @2", DateTime.UtcNow.ToString("s"), expiration, ip) == 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return database.Query("INSERT INTO Bans (IP, Name, UUID, Reason, BanningUser, Date, Expiration, AccountName) VALUES (@0, @1, @2, @3, @4, @5, @6, @7);", ip, name, uuid, reason, banner, DateTime.UtcNow.ToString("s"), expiration, accountName) != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (exceptions)
|
|
||||||
throw ex;
|
|
||||||
TShock.Log.Error(ex.ToString());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes a ban.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns><c>true</c>, if ban was removed, <c>false</c> otherwise.</returns>
|
|
||||||
/// <param name="match">Match.</param>
|
|
||||||
/// <param name="byName">If set to <c>true</c> by name.</param>
|
|
||||||
/// <param name="casesensitive">If set to <c>true</c> casesensitive.</param>
|
|
||||||
/// <param name="exceptions">If set to <c>true</c> exceptions.</param>
|
|
||||||
public bool RemoveBan(string match, bool byName = false, bool casesensitive = true, bool exceptions = false)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!byName)
|
|
||||||
return database.Query("DELETE FROM Bans WHERE IP=@0", match) != 0;
|
|
||||||
|
|
||||||
var namecol = casesensitive ? "Name" : "UPPER(Name)";
|
|
||||||
return database.Query("DELETE FROM Bans WHERE " + namecol + "=@0", casesensitive ? match : match.ToUpper()) != 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (exceptions)
|
|
||||||
throw ex;
|
|
||||||
TShock.Log.Error(ex.ToString());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes a ban by account name (not character/player name).
|
|
||||||
/// </summary>
|
|
||||||
/// <returns><c>true</c>, if ban was removed, <c>false</c> otherwise.</returns>
|
|
||||||
/// <param name="match">Match.</param>
|
|
||||||
/// <param name="casesensitive">If set to <c>true</c> casesensitive.</param>
|
|
||||||
public bool RemoveBanByAccountName(string match, bool casesensitive = true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var namecol = casesensitive ? "AccountName" : "UPPER(AccountName)";
|
|
||||||
return database.Query("DELETE FROM Bans WHERE " + namecol + "=@0", casesensitive ? match : match.ToUpper()) != 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
TShock.Log.Error(ex.ToString());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clears bans.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns><c>true</c>, if bans were cleared, <c>false</c> otherwise.</returns>
|
/// <returns><c>true</c>, if bans were cleared, <c>false</c> otherwise.</returns>
|
||||||
public bool ClearBans()
|
public bool ClearBans()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return database.Query("DELETE FROM Bans") != 0;
|
return database.Query("DELETE FROM PlayerBans") != 0;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -295,19 +292,13 @@ namespace TShockAPI.DB
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Removes a ban if it has expired.</summary>
|
internal Dictionary<BanSortMethod, string> SortToOrderByMap = new Dictionary<BanSortMethod, string>
|
||||||
/// <param name="ban">The candidate ban to check.</param>
|
|
||||||
/// <returns>If the ban has been removed.</returns>
|
|
||||||
public bool RemoveBanIfExpired(Ban ban)
|
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(ban.Expiration) && (ban.ExpirationDateTime != null) && (DateTime.UtcNow >= ban.ExpirationDateTime))
|
{ BanSortMethod.AddedNewestToOldest, "Date DESC" },
|
||||||
{
|
{ BanSortMethod.AddedOldestToNewest, "Date ASC" },
|
||||||
RemoveBan(ban.IP, false, false, false);
|
{ BanSortMethod.ExpirationSoonestToLatest, "Expiration ASC" },
|
||||||
return true;
|
{ BanSortMethod.ExpirationLatestToSoonest, "Expiration DESC" }
|
||||||
}
|
};
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -334,88 +325,18 @@ namespace TShockAPI.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IComparer{Ban}"/> used for sorting an enumerable of bans
|
/// Event args used when a ban check is invoked, or a new ban is added
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BanComparer : IComparer<Ban>
|
public class BanEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
private BanSortMethod _method;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a new <see cref="BanComparer"/> using the given <see cref="BanSortMethod"/>
|
/// The ban being checked or added
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="method"></param>
|
public Ban Ban { get; set; }
|
||||||
public BanComparer(BanSortMethod method)
|
|
||||||
{
|
|
||||||
_method = method;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int CompareDateTimes(DateTime? x, DateTime? y)
|
|
||||||
{
|
|
||||||
if (x == null)
|
|
||||||
{
|
|
||||||
if (y == null)
|
|
||||||
{
|
|
||||||
//If both bans have no BanDateTime they're considered equal
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
//If we're sorting by a newest to oldest method, a null value will come after the valid value.
|
|
||||||
return _method == BanSortMethod.AddedNewestToOldest || _method == BanSortMethod.ExpirationSoonestToLatest ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y == null)
|
|
||||||
{
|
|
||||||
return _method == BanSortMethod.AddedNewestToOldest || _method == BanSortMethod.ExpirationSoonestToLatest ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Newest to oldest sorting uses x compared to y. Oldest to newest uses y compared to x
|
|
||||||
return _method == BanSortMethod.AddedNewestToOldest || _method == BanSortMethod.ExpirationSoonestToLatest ? x.Value.CompareTo(y.Value)
|
|
||||||
: y.Value.CompareTo(x.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compares two ban objects
|
/// Whether or not the operation is valid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="x"></param>
|
public bool Valid { get; set; } = true;
|
||||||
/// <param name="y"></param>
|
|
||||||
/// <returns>1 if x is less than y, 0 if x is equal to y, -1 if x is greater than y</returns>
|
|
||||||
public int Compare(Ban x, Ban y)
|
|
||||||
{
|
|
||||||
if (x == null)
|
|
||||||
{
|
|
||||||
if (y == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If Ban y is null and Ban x is not, and we're sorting from newest to oldest, x goes before y. Else y goes before x
|
|
||||||
return _method == BanSortMethod.AddedNewestToOldest || _method == BanSortMethod.ExpirationSoonestToLatest ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x == null)
|
|
||||||
{
|
|
||||||
if (y == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If Ban y is null and Ban x is not, and we're sorting from newest to oldest, x goes before y. Else y goes before x
|
|
||||||
return _method == BanSortMethod.AddedNewestToOldest || _method == BanSortMethod.ExpirationSoonestToLatest ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (_method)
|
|
||||||
{
|
|
||||||
case BanSortMethod.AddedNewestToOldest:
|
|
||||||
case BanSortMethod.AddedOldestToNewest:
|
|
||||||
return CompareDateTimes(x.BanDateTime, y.BanDateTime);
|
|
||||||
|
|
||||||
case BanSortMethod.ExpirationSoonestToLatest:
|
|
||||||
case BanSortMethod.ExpirationLatestToSoonest:
|
|
||||||
return CompareDateTimes(x.ExpirationDateTime, y.ExpirationDateTime);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -424,28 +345,32 @@ namespace TShockAPI.DB
|
||||||
public class Ban
|
public class Ban
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the IP address of the ban entry.
|
/// Contains constants for different identifier types known to TShock
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The IP Address</value>
|
public class Identifiers
|
||||||
public string IP { get; set; }
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// IP identifier prefix constant
|
||||||
|
/// </summary>
|
||||||
|
public const string IP = "ip:";
|
||||||
|
/// <summary>
|
||||||
|
/// UUID identifier prefix constant
|
||||||
|
/// </summary>
|
||||||
|
public const string UUID = "uuid:";
|
||||||
|
/// <summary>
|
||||||
|
/// Player name identifier prefix constant
|
||||||
|
/// </summary>
|
||||||
|
public const string Name = "name:";
|
||||||
|
/// <summary>
|
||||||
|
/// User account identifier prefix constant
|
||||||
|
/// </summary>
|
||||||
|
public const string Account = "acc:";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the name.
|
/// An identifiable piece of information to ban
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The name.</value>
|
public string Identifier { get; set; }
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the Client UUID of the ban
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The UUID</value>
|
|
||||||
public string UUID { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the account name of the ban
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The account name</value>
|
|
||||||
public String AccountName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the ban reason.
|
/// Gets or sets the ban reason.
|
||||||
|
|
@ -460,73 +385,46 @@ namespace TShockAPI.DB
|
||||||
public string BanningUser { get; set; }
|
public string BanningUser { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the UTC date of when the ban is to take effect
|
/// DateTime from which the ban will take effect
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The date, which must be in UTC</value>
|
public DateTime BanDateTime { get; }
|
||||||
public string Date { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="System.DateTime"/> object representation of the <see cref="Date"/> string.
|
/// DateTime at which the ban will end
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime? BanDateTime { get; }
|
public DateTime ExpirationDateTime { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the expiration date, in which the ban shall be lifted
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The expiration.</value>
|
|
||||||
public string Expiration { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="System.DateTime"/> object representation of the <see cref="Expiration"/> string.
|
|
||||||
/// </summary>
|
|
||||||
public DateTime? ExpirationDateTime { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="TShockAPI.DB.Ban"/> class.
|
/// Initializes a new instance of the <see cref="TShockAPI.DB.Ban"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ip">Ip.</param>
|
/// <param name="identifier">Identifier to apply the ban to</param>
|
||||||
/// <param name="name">Name.</param>
|
/// <param name="reason">Reason for the ban</param>
|
||||||
/// <param name="uuid">UUID.</param>
|
/// <param name="banningUser">Account name that executed the ban</param>
|
||||||
/// <param name="reason">Reason.</param>
|
/// <param name="start">Ban start datetime</param>
|
||||||
/// <param name="banner">Banner.</param>
|
/// <param name="end">Ban end datetime</param>
|
||||||
/// <param name="date">UTC ban date.</param>
|
public Ban(string identifier, string reason, string banningUser, string start, string end)
|
||||||
/// <param name="exp">Expiration time</param>
|
|
||||||
public Ban(string ip, string name, string uuid, string accountName, string reason, string banner, string date, string exp)
|
|
||||||
{
|
{
|
||||||
IP = ip;
|
Identifier = identifier;
|
||||||
Name = name;
|
|
||||||
UUID = uuid;
|
|
||||||
AccountName = accountName;
|
|
||||||
Reason = reason;
|
Reason = reason;
|
||||||
BanningUser = banner;
|
BanningUser = banningUser;
|
||||||
Date = date;
|
|
||||||
Expiration = exp;
|
|
||||||
|
|
||||||
DateTime d;
|
if (DateTime.TryParse(start, out DateTime d))
|
||||||
DateTime e;
|
|
||||||
if (DateTime.TryParse(Date, out d))
|
|
||||||
{
|
{
|
||||||
BanDateTime = d;
|
BanDateTime = d;
|
||||||
}
|
}
|
||||||
if (DateTime.TryParse(Expiration, out e))
|
else
|
||||||
|
{
|
||||||
|
BanDateTime = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DateTime.TryParse(end, out DateTime e))
|
||||||
{
|
{
|
||||||
ExpirationDateTime = e;
|
ExpirationDateTime = e;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
/// <summary>
|
ExpirationDateTime = DateTime.MaxValue;
|
||||||
/// Initializes a new instance of the <see cref="TShockAPI.DB.Ban"/> class.
|
}
|
||||||
/// </summary>
|
|
||||||
public Ban()
|
|
||||||
{
|
|
||||||
IP = string.Empty;
|
|
||||||
Name = string.Empty;
|
|
||||||
UUID = string.Empty;
|
|
||||||
AccountName = string.Empty;
|
|
||||||
Reason = string.Empty;
|
|
||||||
BanningUser = string.Empty;
|
|
||||||
Date = string.Empty;
|
|
||||||
Expiration = string.Empty;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace TShockAPI
|
namespace TShockAPI
|
||||||
{
|
{
|
||||||
|
|
@ -31,5 +32,25 @@ namespace TShockAPI
|
||||||
foreach (T item in source)
|
foreach (T item in source)
|
||||||
action(item);
|
action(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to retrieve the value at the given index from the enumerable
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="enumerable"></param>
|
||||||
|
/// <param name="index"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool TryGetValue<T>(this IEnumerable<T> enumerable, int index, out T value)
|
||||||
|
{
|
||||||
|
if (index < enumerable.Count())
|
||||||
|
{
|
||||||
|
value = enumerable.ElementAt(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3592,7 +3592,7 @@ namespace TShockAPI
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool HandleKillPortal(GetDataHandlerArgs args)
|
private static bool HandleKillPortal(GetDataHandlerArgs args)
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ namespace TShockAPI
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of <see cref="Token"/>
|
/// Creates a new instance of <see cref="Token"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Token() : base("token", true, "The REST authentication token.", typeof(String)){}
|
public Token() : base("token", true, "The REST authentication token.", typeof(String)) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -216,9 +216,13 @@ namespace TShockAPI
|
||||||
Rest.RegisterRedirect("/users/update", "/v2/users/update");
|
Rest.RegisterRedirect("/users/update", "/v2/users/update");
|
||||||
|
|
||||||
//ban commands
|
//ban commands
|
||||||
Rest.RegisterRedirect("/bans/list", "/v2/bans/list");
|
Rest.RegisterRedirect("/bans/create", "/v3/bans/create");
|
||||||
Rest.RegisterRedirect("/bans/read", "/v2/bans/read");
|
Rest.RegisterRedirect("/bans/list", "/v3/bans/list");
|
||||||
Rest.RegisterRedirect("/bans/destroy", "/v2/bans/destroy");
|
Rest.RegisterRedirect("/bans/read", "/v3/bans/read");
|
||||||
|
Rest.RegisterRedirect("/bans/destroy", "/v3/bans/destroy");
|
||||||
|
Rest.RegisterRedirect("/v2/bans/list", "/v3/bans/list");
|
||||||
|
Rest.RegisterRedirect("/v2/bans/read", "/v3/bans/read");
|
||||||
|
Rest.RegisterRedirect("/v2/bans/destroy", "/v3/bans/destroy");
|
||||||
|
|
||||||
//world commands
|
//world commands
|
||||||
Rest.RegisterRedirect("/world/bloodmoon", "v3/world/bloodmoon");
|
Rest.RegisterRedirect("/world/bloodmoon", "v3/world/bloodmoon");
|
||||||
|
|
@ -258,10 +262,10 @@ namespace TShockAPI
|
||||||
Rest.Register(new SecureRestCommand("/v2/users/update", UserUpdateV2, RestPermissions.restmanageusers) { DoLog = false });
|
Rest.Register(new SecureRestCommand("/v2/users/update", UserUpdateV2, RestPermissions.restmanageusers) { DoLog = false });
|
||||||
|
|
||||||
// Ban Commands
|
// Ban Commands
|
||||||
Rest.Register(new SecureRestCommand("/bans/create", BanCreate, RestPermissions.restmanagebans));
|
Rest.Register(new SecureRestCommand("/v3/bans/create", BanCreateV3, RestPermissions.restban, RestPermissions.restmanagebans));
|
||||||
Rest.Register(new SecureRestCommand("/v2/bans/list", BanListV2, RestPermissions.restviewbans));
|
Rest.Register(new SecureRestCommand("/v3/bans/list", BanListV3, RestPermissions.restviewbans));
|
||||||
Rest.Register(new SecureRestCommand("/v2/bans/read", BanInfoV2, RestPermissions.restviewbans));
|
Rest.Register(new SecureRestCommand("/v3/bans/read", BanInfoV3, RestPermissions.restviewbans));
|
||||||
Rest.Register(new SecureRestCommand("/v2/bans/destroy", BanDestroyV2, RestPermissions.restmanagebans));
|
Rest.Register(new SecureRestCommand("/v3/bans/destroy", BanDestroyV3, RestPermissions.restmanagebans));
|
||||||
|
|
||||||
// World Commands
|
// World Commands
|
||||||
Rest.Register(new SecureRestCommand("/world/read", WorldRead));
|
Rest.Register(new SecureRestCommand("/world/read", WorldRead));
|
||||||
|
|
@ -279,7 +283,6 @@ namespace TShockAPI
|
||||||
Rest.Register(new SecureRestCommand("/v3/players/read", PlayerReadV3, RestPermissions.restuserinfo));
|
Rest.Register(new SecureRestCommand("/v3/players/read", PlayerReadV3, RestPermissions.restuserinfo));
|
||||||
Rest.Register(new SecureRestCommand("/v4/players/read", PlayerReadV4, RestPermissions.restuserinfo));
|
Rest.Register(new SecureRestCommand("/v4/players/read", PlayerReadV4, RestPermissions.restuserinfo));
|
||||||
Rest.Register(new SecureRestCommand("/v2/players/kick", PlayerKickV2, RestPermissions.restkick));
|
Rest.Register(new SecureRestCommand("/v2/players/kick", PlayerKickV2, RestPermissions.restkick));
|
||||||
Rest.Register(new SecureRestCommand("/v2/players/ban", PlayerBanV2, RestPermissions.restban, RestPermissions.restmanagebans));
|
|
||||||
Rest.Register(new SecureRestCommand("/v2/players/kill", PlayerKill, RestPermissions.restkill));
|
Rest.Register(new SecureRestCommand("/v2/players/kill", PlayerKill, RestPermissions.restkill));
|
||||||
Rest.Register(new SecureRestCommand("/v2/players/mute", PlayerMute, RestPermissions.restmute));
|
Rest.Register(new SecureRestCommand("/v2/players/mute", PlayerMute, RestPermissions.restmute));
|
||||||
Rest.Register(new SecureRestCommand("/v2/players/unmute", PlayerUnMute, RestPermissions.restmute));
|
Rest.Register(new SecureRestCommand("/v2/players/unmute", PlayerUnMute, RestPermissions.restmute));
|
||||||
|
|
@ -420,7 +423,7 @@ namespace TShockAPI
|
||||||
|
|
||||||
if (GetBool(args.Parameters["rules"], false))
|
if (GetBool(args.Parameters["rules"], false))
|
||||||
{
|
{
|
||||||
var rules = new Dictionary<string,object>();
|
var rules = new Dictionary<string, object>();
|
||||||
rules.Add("AutoSave", TShock.Config.AutoSave);
|
rules.Add("AutoSave", TShock.Config.AutoSave);
|
||||||
rules.Add("DisableBuild", TShock.Config.DisableBuild);
|
rules.Add("DisableBuild", TShock.Config.DisableBuild);
|
||||||
rules.Add("DisableClownBombs", TShock.Config.DisableClownBombs);
|
rules.Add("DisableClownBombs", TShock.Config.DisableClownBombs);
|
||||||
|
|
@ -492,8 +495,8 @@ namespace TShockAPI
|
||||||
return RestMissingParam("user");
|
return RestMissingParam("user");
|
||||||
|
|
||||||
var group = args.Parameters["group"];
|
var group = args.Parameters["group"];
|
||||||
if (string.IsNullOrWhiteSpace(group))
|
if (string.IsNullOrWhiteSpace(group))
|
||||||
group = TShock.Config.DefaultRegistrationGroupName;
|
group = TShock.Config.DefaultRegistrationGroupName;
|
||||||
|
|
||||||
var password = args.Parameters["password"];
|
var password = args.Parameters["password"];
|
||||||
if (string.IsNullOrWhiteSpace(password))
|
if (string.IsNullOrWhiteSpace(password))
|
||||||
|
|
@ -609,115 +612,141 @@ namespace TShockAPI
|
||||||
#region Rest Ban Methods
|
#region Rest Ban Methods
|
||||||
|
|
||||||
[Description("Create a new ban entry.")]
|
[Description("Create a new ban entry.")]
|
||||||
[Route("/bans/create")]
|
[Route("/v3/bans/create")]
|
||||||
[Permission(RestPermissions.restmanagebans)]
|
[Permission(RestPermissions.restmanagebans)]
|
||||||
[Noun("ip", false, "The IP to ban, at least this or name must be specified.", typeof(String))]
|
[Noun("identifier", true, "The identifier to ban.", typeof(String))]
|
||||||
[Noun("name", false, "The name to ban, at least this or ip must be specified.", typeof(String))]
|
|
||||||
[Noun("reason", false, "The reason to assign to the ban.", typeof(String))]
|
[Noun("reason", false, "The reason to assign to the ban.", typeof(String))]
|
||||||
|
[Noun("start", false, "The datetime at which the ban should start.", typeof(String))]
|
||||||
|
[Noun("end", false, "The datetime at which the ban should end.", typeof(String))]
|
||||||
[Token]
|
[Token]
|
||||||
private object BanCreate(RestRequestArgs args)
|
private object BanCreateV3(RestRequestArgs args)
|
||||||
{
|
{
|
||||||
var ip = args.Parameters["ip"];
|
string identifier = args.Parameters["identifier"];
|
||||||
var name = args.Parameters["name"];
|
if (string.IsNullOrWhiteSpace(identifier))
|
||||||
|
return RestMissingParam("identifier");
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(ip) && string.IsNullOrWhiteSpace(name))
|
string reason = args.Parameters["reason"];
|
||||||
return RestMissingParam("ip", "name");
|
if (string.IsNullOrWhiteSpace(reason))
|
||||||
|
reason = "Banned";
|
||||||
|
|
||||||
try
|
if (!DateTime.TryParse(args.Parameters["start"], out DateTime startDate))
|
||||||
|
startDate = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if (!DateTime.TryParse(args.Parameters["end"], out DateTime endDate))
|
||||||
|
endDate = DateTime.MaxValue;
|
||||||
|
|
||||||
|
if (TShock.Bans.InsertBan(identifier, reason, args.TokenData.Username, startDate, endDate) != null)
|
||||||
{
|
{
|
||||||
TShock.Bans.AddBan(ip, name, "", "", args.Parameters["reason"], true, args.TokenData.Username);
|
TSPlayer player = null;
|
||||||
|
if (identifier.StartsWith(Ban.Identifiers.IP))
|
||||||
|
{
|
||||||
|
player = TShock.Players.FirstOrDefault(p => p.IP == identifier.Substring(Ban.Identifiers.IP.Length));
|
||||||
|
}
|
||||||
|
else if (identifier.StartsWith(Ban.Identifiers.Name))
|
||||||
|
{
|
||||||
|
//Character names may not necessarily be unique, so kick all matches
|
||||||
|
foreach (var ply in TShock.Players.Where(p => p.Name == identifier.Substring(Ban.Identifiers.Name.Length)))
|
||||||
|
{
|
||||||
|
ply.Kick(reason, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (identifier.StartsWith(Ban.Identifiers.Account))
|
||||||
|
{
|
||||||
|
player = TShock.Players.FirstOrDefault(p => p.Account?.Name == identifier.Substring(Ban.Identifiers.Account.Length));
|
||||||
|
}
|
||||||
|
else if (identifier.StartsWith(Ban.Identifiers.UUID))
|
||||||
|
{
|
||||||
|
player = TShock.Players.FirstOrDefault(p => p.UUID == identifier.Substring(Ban.Identifiers.UUID.Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
player.Kick(reason, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RestResponse("Ban added.");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
return RestError("Failed to add ban.", status: "500");
|
||||||
return RestError(e.Message);
|
|
||||||
}
|
|
||||||
return RestResponse("Ban created successfully");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Description("Delete an existing ban entry.")]
|
[Description("Delete an existing ban entry.")]
|
||||||
[Route("/v2/bans/destroy")]
|
[Route("/v3/bans/destroy")]
|
||||||
[Permission(RestPermissions.restmanagebans)]
|
[Permission(RestPermissions.restmanagebans)]
|
||||||
[Noun("ban", true, "The search criteria, either an IP address or a name.", typeof(String))]
|
[Noun("identifier", true, "The identifier of the ban to delete.", typeof(String))]
|
||||||
[Noun("type", true, "The type of search criteria, 'ip' or 'name'. Also used as the method of removing from the database.", typeof(String))]
|
[Noun("fullDelete", false, "Whether or not to completely remove the ban from the system.", typeof(bool))]
|
||||||
[Noun("caseinsensitive", false, "Name lookups should be case insensitive.", typeof(bool))]
|
|
||||||
[Token]
|
[Token]
|
||||||
private object BanDestroyV2(RestRequestArgs args)
|
private object BanDestroyV3(RestRequestArgs args)
|
||||||
{
|
{
|
||||||
var ret = BanFind(args.Parameters);
|
string identifier = args.Parameters["identifier"];
|
||||||
if (ret is RestObject)
|
if (string.IsNullOrWhiteSpace(identifier))
|
||||||
return ret;
|
return RestMissingParam("identifier");
|
||||||
|
|
||||||
try
|
bool.TryParse(args.Parameters["fullDelete"], out bool fullDelete);
|
||||||
{
|
|
||||||
Ban ban = (Ban)ret;
|
|
||||||
switch (args.Parameters["type"])
|
|
||||||
{
|
|
||||||
case "ip":
|
|
||||||
if (!TShock.Bans.RemoveBan(ban.IP, false, false, true))
|
|
||||||
return RestResponse("Failed to delete ban (already deleted?)");
|
|
||||||
break;
|
|
||||||
case "name":
|
|
||||||
if (!TShock.Bans.RemoveBan(ban.Name, true, GetBool(args.Parameters["caseinsensitive"], true)))
|
|
||||||
return RestResponse("Failed to delete ban (already deleted?)");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return RestError("Invalid Type: '" + args.Parameters["type"] + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
if (TShock.Bans.RemoveBan(identifier, fullDelete))
|
||||||
catch (Exception e)
|
|
||||||
{
|
{
|
||||||
return RestError(e.Message);
|
return RestResponse("Ban removed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return RestResponse("Ban deleted successfully");
|
return RestError("Failed to remove ban.", status: "500");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Description("View the details of a specific ban.")]
|
[Description("View the details of a specific ban.")]
|
||||||
[Route("/v2/bans/read")]
|
[Route("/v3/bans/read")]
|
||||||
[Permission(RestPermissions.restviewbans)]
|
[Permission(RestPermissions.restviewbans)]
|
||||||
[Noun("ban", true, "The search criteria, either an IP address or a name.", typeof(String))]
|
[Noun("identifier", true, "The identifier to search for.", typeof(String))]
|
||||||
[Noun("type", true, "The type of search criteria, 'ip' or 'name'.", typeof(String))]
|
|
||||||
[Noun("caseinsensitive", false, "Name lookups should be case insensitive.", typeof(bool))]
|
|
||||||
[Token]
|
[Token]
|
||||||
private object BanInfoV2(RestRequestArgs args)
|
private object BanInfoV3(RestRequestArgs args)
|
||||||
{
|
{
|
||||||
var ret = BanFind(args.Parameters);
|
string identifier = args.Parameters["identifier"];
|
||||||
if (ret is RestObject)
|
if (string.IsNullOrWhiteSpace(identifier))
|
||||||
return ret;
|
return RestMissingParam("identifier");
|
||||||
|
|
||||||
Ban ban = (Ban)ret;
|
Ban ban = TShock.Bans.GetBanByIdentifier(identifier);
|
||||||
return new RestObject() {
|
|
||||||
{"name", null == ban.Name ? "" : ban.Name},
|
if (ban == null)
|
||||||
{"ip", null == ban.IP ? "" : ban.IP},
|
{
|
||||||
{"banning_user", null == ban.BanningUser ? "" : ban.BanningUser},
|
return RestResponse("No matching bans found.");
|
||||||
{"date", null == ban.BanDateTime ? "" : ban.BanDateTime.Value.ToString()},
|
}
|
||||||
{"reason", null == ban.Reason ? "" : ban.Reason},
|
|
||||||
|
return new RestObject
|
||||||
|
{
|
||||||
|
{"identifier", ban.Identifier },
|
||||||
|
{"reason", ban.Reason },
|
||||||
|
{"banning_user", ban.BanningUser },
|
||||||
|
{"fromDate", ban.BanDateTime.ToString("s") },
|
||||||
|
{"toDate", ban.ExpirationDateTime.ToString("s") },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[Description("View all bans in the TShock database.")]
|
[Description("View all bans in the TShock database.")]
|
||||||
[Route("/v2/bans/list")]
|
[Route("/v3/bans/list")]
|
||||||
[Permission(RestPermissions.restviewbans)]
|
[Permission(RestPermissions.restviewbans)]
|
||||||
[Token]
|
[Token]
|
||||||
private object BanListV2(RestRequestArgs args)
|
private object BanListV3(RestRequestArgs args)
|
||||||
{
|
{
|
||||||
|
IEnumerable<Ban> bans = TShock.Bans.GetAllBans();
|
||||||
|
|
||||||
var banList = new ArrayList();
|
var banList = new ArrayList();
|
||||||
foreach (var ban in TShock.Bans.GetBans())
|
foreach (var ban in bans)
|
||||||
{
|
{
|
||||||
banList.Add(
|
banList.Add(
|
||||||
new Dictionary<string, string>
|
new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{"name", null == ban.Name ? "" : ban.Name},
|
{"identifier", ban.Identifier },
|
||||||
{"ip", null == ban.IP ? "" : ban.IP},
|
{"reason", ban.Reason },
|
||||||
{"banning_user", null == ban.BanningUser ? "" : ban.BanningUser},
|
{"banning_user", ban.BanningUser },
|
||||||
{"date", null == ban.BanDateTime ? "" : ban.BanDateTime.Value.ToString()},
|
{"fromDate", ban.BanDateTime.ToString("s") },
|
||||||
{"reason", null == ban.Reason ? "" : ban.Reason},
|
{"toDate", ban.ExpirationDateTime.ToString("s") },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RestObject() { { "bans", banList } };
|
return new RestObject
|
||||||
|
{
|
||||||
|
{ "bans", banList }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
@ -987,26 +1016,6 @@ namespace TShockAPI
|
||||||
return RestResponse("Player " + player.Name + " was kicked");
|
return RestResponse("Player " + player.Name + " was kicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Description("Add a ban to the database.")]
|
|
||||||
[Route("/v2/players/ban")]
|
|
||||||
[Permission(RestPermissions.restban)]
|
|
||||||
[Permission(RestPermissions.restmanagebans)]
|
|
||||||
[Noun("player", true, "The player to kick.", typeof(String))]
|
|
||||||
[Noun("reason", false, "The reason the user was banned.", typeof(String))]
|
|
||||||
[Token]
|
|
||||||
private object PlayerBanV2(RestRequestArgs args)
|
|
||||||
{
|
|
||||||
var ret = PlayerFind(args.Parameters);
|
|
||||||
if (ret is RestObject)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
TSPlayer player = (TSPlayer)ret;
|
|
||||||
var reason = null == args.Parameters["reason"] ? "Banned via web" : args.Parameters["reason"];
|
|
||||||
TShock.Bans.AddBan(player.IP, player.Name, "", "", reason);
|
|
||||||
player.Kick(reason, true, false, null, true);
|
|
||||||
return RestResponse("Player " + player.Name + " was banned");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Description("Kill a player.")]
|
[Description("Kill a player.")]
|
||||||
[Route("/v2/players/kill")]
|
[Route("/v2/players/kill")]
|
||||||
[Permission(RestPermissions.restkill)]
|
[Permission(RestPermissions.restkill)]
|
||||||
|
|
@ -1039,7 +1048,7 @@ namespace TShockAPI
|
||||||
var groups = new ArrayList();
|
var groups = new ArrayList();
|
||||||
foreach (Group group in TShock.Groups)
|
foreach (Group group in TShock.Groups)
|
||||||
{
|
{
|
||||||
groups.Add(new Dictionary<string, object> {{"name", group.Name}, {"parent", group.ParentName}, {"chatcolor", group.ChatColor}});
|
groups.Add(new Dictionary<string, object> { { "name", group.Name }, { "parent", group.ParentName }, { "chatcolor", group.ChatColor } });
|
||||||
}
|
}
|
||||||
return new RestObject() { { "groups", groups } };
|
return new RestObject() { { "groups", groups } };
|
||||||
}
|
}
|
||||||
|
|
@ -1200,7 +1209,7 @@ namespace TShockAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.AppendLine("Example Usage: {0}?{1}".SFormat(routeattr.Route,
|
sb.AppendLine("Example Usage: {0}?{1}".SFormat(routeattr.Route,
|
||||||
string.Join("&", nouns.Select(n => String.Format("{0}={0}", ((Noun) n).Name)))));
|
string.Join("&", nouns.Select(n => String.Format("{0}={0}", ((Noun)n).Name)))));
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1210,12 +1219,12 @@ namespace TShockAPI
|
||||||
|
|
||||||
private RestObject RestError(string message, string status = "400")
|
private RestObject RestError(string message, string status = "400")
|
||||||
{
|
{
|
||||||
return new RestObject(status) {Error = message};
|
return new RestObject(status) { Error = message };
|
||||||
}
|
}
|
||||||
|
|
||||||
private RestObject RestResponse(string message, string status = "200")
|
private RestObject RestResponse(string message, string status = "200")
|
||||||
{
|
{
|
||||||
return new RestObject(status) {Response = message};
|
return new RestObject(status) { Response = message };
|
||||||
}
|
}
|
||||||
|
|
||||||
private RestObject RestMissingParam(string var)
|
private RestObject RestMissingParam(string var)
|
||||||
|
|
@ -1246,7 +1255,7 @@ namespace TShockAPI
|
||||||
return RestMissingParam("player");
|
return RestMissingParam("player");
|
||||||
|
|
||||||
var found = TSPlayer.FindByNameOrID(name);
|
var found = TSPlayer.FindByNameOrID(name);
|
||||||
switch(found.Count)
|
switch (found.Count)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return found[0];
|
return found[0];
|
||||||
|
|
@ -1292,35 +1301,6 @@ namespace TShockAPI
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object BanFind(IParameterCollection parameters)
|
|
||||||
{
|
|
||||||
string name = parameters["ban"];
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
|
||||||
return RestMissingParam("ban");
|
|
||||||
|
|
||||||
string type = parameters["type"];
|
|
||||||
if (string.IsNullOrWhiteSpace(type))
|
|
||||||
return RestMissingParam("type");
|
|
||||||
|
|
||||||
Ban ban;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "ip":
|
|
||||||
ban = TShock.Bans.GetBanByIp(name);
|
|
||||||
break;
|
|
||||||
case "name":
|
|
||||||
ban = TShock.Bans.GetBanByName(name, GetBool(parameters["caseinsensitive"], true));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return RestError("Invalid Type: '" + type + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null == ban)
|
|
||||||
return RestError("Ban " + type + " '" + name + "' doesn't exist");
|
|
||||||
|
|
||||||
return ban;
|
|
||||||
}
|
|
||||||
|
|
||||||
private object GroupFind(IParameterCollection parameters)
|
private object GroupFind(IParameterCollection parameters)
|
||||||
{
|
{
|
||||||
var name = parameters["group"];
|
var name = parameters["group"];
|
||||||
|
|
|
||||||
|
|
@ -1638,9 +1638,13 @@ namespace TShockAPI
|
||||||
return true;
|
return true;
|
||||||
if (force || !HasPermission(Permissions.immunetoban))
|
if (force || !HasPermission(Permissions.immunetoban))
|
||||||
{
|
{
|
||||||
string ip = IP;
|
TShock.Bans.InsertBan($"{DB.Ban.Identifiers.IP}{IP}", reason, adminUserName, DateTime.UtcNow, DateTime.MaxValue);
|
||||||
string uuid = UUID;
|
TShock.Bans.InsertBan($"{DB.Ban.Identifiers.IP}{UUID}", reason, adminUserName, DateTime.UtcNow, DateTime.MaxValue);
|
||||||
TShock.Bans.AddBan(ip, Name, uuid, "", reason, false, adminUserName);
|
if (Account != null)
|
||||||
|
{
|
||||||
|
TShock.Bans.InsertBan($"{DB.Ban.Identifiers.Account}{Account.Name}", reason, adminUserName, DateTime.UtcNow, DateTime.MaxValue);
|
||||||
|
}
|
||||||
|
|
||||||
Disconnect(string.Format("Banned: {0}", reason));
|
Disconnect(string.Format("Banned: {0}", reason));
|
||||||
string verb = force ? "force " : "";
|
string verb = force ? "force " : "";
|
||||||
if (string.IsNullOrWhiteSpace(adminUserName))
|
if (string.IsNullOrWhiteSpace(adminUserName))
|
||||||
|
|
|
||||||
|
|
@ -478,26 +478,13 @@ namespace TShockAPI
|
||||||
args.Player.Account.KnownIps = JsonConvert.SerializeObject(KnownIps, Formatting.Indented);
|
args.Player.Account.KnownIps = JsonConvert.SerializeObject(KnownIps, Formatting.Indented);
|
||||||
UserAccounts.UpdateLogin(args.Player.Account);
|
UserAccounts.UpdateLogin(args.Player.Account);
|
||||||
|
|
||||||
Ban potentialBan = Bans.GetBanByAccountName(args.Player.Account.Name);
|
//Check if this user has any recorded bans
|
||||||
|
var validBan = Bans.GetBansByIdentifiers($"acc:{args.Player.Account.Name}", $"uuid:{args.Player.UUID}").FirstOrDefault(b => Bans.IsValidBan(b));
|
||||||
|
|
||||||
if (potentialBan != null)
|
//If they do and any are still valid, kick them
|
||||||
|
if (validBan != null)
|
||||||
{
|
{
|
||||||
// A user just signed in successfully despite being banned by account name.
|
args.Player.Kick($"You are banned: {validBan.Reason}", true, true);
|
||||||
// We should fix the ban database so that all of their ban info is up to date.
|
|
||||||
Bans.AddBan(args.Player.IP, args.Player.Name, args.Player.UUID, args.Player.Account.Name,
|
|
||||||
potentialBan.Reason, false, potentialBan.BanningUser, potentialBan.Expiration);
|
|
||||||
|
|
||||||
// And then get rid of them.
|
|
||||||
if (potentialBan.Expiration == "")
|
|
||||||
{
|
|
||||||
args.Player.Kick(String.Format("Permanently banned by {0} for {1}", potentialBan.BanningUser
|
|
||||||
,potentialBan.Reason), true, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args.Player.Kick(String.Format("Still banned by {0} for {1}", potentialBan.BanningUser,
|
|
||||||
potentialBan.Reason), true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -816,7 +803,7 @@ namespace TShockAPI
|
||||||
Console.WriteLine("Startup parameter overrode REST port.");
|
Console.WriteLine("Startup parameter overrode REST port.");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.AddFlags(playerSet, (p)=>
|
.AddFlags(playerSet, (p) =>
|
||||||
{
|
{
|
||||||
int slots;
|
int slots;
|
||||||
if (int.TryParse(p, out slots))
|
if (int.TryParse(p, out slots))
|
||||||
|
|
@ -1100,7 +1087,7 @@ namespace TShockAPI
|
||||||
if (args.Handled)
|
if (args.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(!OnCreep(args.Grass))
|
if (!OnCreep(args.Grass))
|
||||||
{
|
{
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1209,65 +1196,45 @@ namespace TShockAPI
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ban ban = null;
|
Ban ban = Bans.GetBansByIdentifiers($"name:{player.Name}", $"uuid:{player.UUID}", $"ip:{player.IP}").FirstOrDefault(b => Bans.IsValidBan(b));
|
||||||
if (Config.EnableBanOnUsernames)
|
|
||||||
{
|
|
||||||
var newban = Bans.GetBanByName(player.Name);
|
|
||||||
if (null != newban)
|
|
||||||
ban = newban;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.EnableIPBans && null == ban)
|
|
||||||
{
|
|
||||||
ban = Bans.GetBanByIp(player.IP);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.EnableUUIDBans && null == ban && !String.IsNullOrWhiteSpace(player.UUID))
|
|
||||||
{
|
|
||||||
ban = Bans.GetBanByUUID(player.UUID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ban != null)
|
if (ban != null)
|
||||||
{
|
{
|
||||||
if (!Bans.RemoveBanIfExpired(ban))
|
if (ban.ExpirationDateTime == DateTime.MaxValue)
|
||||||
{
|
{
|
||||||
DateTime exp;
|
player.Disconnect("You are banned: " + ban.Reason);
|
||||||
if (!DateTime.TryParse(ban.Expiration, out exp))
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TimeSpan ts = ban.ExpirationDateTime - DateTime.UtcNow;
|
||||||
|
int months = ts.Days / 30;
|
||||||
|
if (months > 0)
|
||||||
{
|
{
|
||||||
player.Disconnect("Permanently banned for: " + ban.Reason);
|
player.Disconnect(String.Format("You are banned for {0} month{1} and {2} day{3}: {4}",
|
||||||
|
months, months == 1 ? "" : "s", ts.Days, ts.Days == 1 ? "" : "s", ban.Reason));
|
||||||
|
}
|
||||||
|
else if (ts.Days > 0)
|
||||||
|
{
|
||||||
|
player.Disconnect(String.Format("You are banned for {0} day{1} and {2} hour{3}: {4}",
|
||||||
|
ts.Days, ts.Days == 1 ? "" : "s", ts.Hours, ts.Hours == 1 ? "" : "s", ban.Reason));
|
||||||
|
}
|
||||||
|
else if (ts.Hours > 0)
|
||||||
|
{
|
||||||
|
player.Disconnect(String.Format("You are banned for {0} hour{1} and {2} minute{3}: {4}",
|
||||||
|
ts.Hours, ts.Hours == 1 ? "" : "s", ts.Minutes, ts.Minutes == 1 ? "" : "s", ban.Reason));
|
||||||
|
}
|
||||||
|
else if (ts.Minutes > 0)
|
||||||
|
{
|
||||||
|
player.Disconnect(String.Format("You are banned for {0} minute{1} and {2} second{3}: {4}",
|
||||||
|
ts.Minutes, ts.Minutes == 1 ? "" : "s", ts.Seconds, ts.Seconds == 1 ? "" : "s", ban.Reason));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TimeSpan ts = exp - DateTime.UtcNow;
|
player.Disconnect(String.Format("You are banned for {0} second{1}: {2}",
|
||||||
int months = ts.Days / 30;
|
ts.Seconds, ts.Seconds == 1 ? "" : "s", ban.Reason));
|
||||||
if (months > 0)
|
|
||||||
{
|
|
||||||
player.Disconnect(String.Format("You are banned for {0} month{1} and {2} day{3}: {4}",
|
|
||||||
months, months == 1 ? "" : "s", ts.Days, ts.Days == 1 ? "" : "s", ban.Reason));
|
|
||||||
}
|
|
||||||
else if (ts.Days > 0)
|
|
||||||
{
|
|
||||||
player.Disconnect(String.Format("You are banned for {0} day{1} and {2} hour{3}: {4}",
|
|
||||||
ts.Days, ts.Days == 1 ? "" : "s", ts.Hours, ts.Hours == 1 ? "" : "s", ban.Reason));
|
|
||||||
}
|
|
||||||
else if (ts.Hours > 0)
|
|
||||||
{
|
|
||||||
player.Disconnect(String.Format("You are banned for {0} hour{1} and {2} minute{3}: {4}",
|
|
||||||
ts.Hours, ts.Hours == 1 ? "" : "s", ts.Minutes, ts.Minutes == 1 ? "" : "s", ban.Reason));
|
|
||||||
}
|
|
||||||
else if (ts.Minutes > 0)
|
|
||||||
{
|
|
||||||
player.Disconnect(String.Format("You are banned for {0} minute{1} and {2} second{3}: {4}",
|
|
||||||
ts.Minutes, ts.Minutes == 1 ? "" : "s", ts.Seconds, ts.Seconds == 1 ? "" : "s", ban.Reason));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
player.Disconnect(String.Format("You are banned for {0} second{1}: {2}",
|
|
||||||
ts.Seconds, ts.Seconds == 1 ? "" : "s", ban.Reason));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
args.Handled = true;
|
|
||||||
}
|
}
|
||||||
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1647,7 +1614,8 @@ namespace TShockAPI
|
||||||
player.RecentlyCreatedProjectiles.RemoveAll(p => p.Index == e.number && p.Killed);
|
player.RecentlyCreatedProjectiles.RemoveAll(p => p.Index == e.number && p.Killed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player.RecentlyCreatedProjectiles.Any(p => p.Index == e.number)) {
|
if (!player.RecentlyCreatedProjectiles.Any(p => p.Index == e.number))
|
||||||
|
{
|
||||||
player.RecentlyCreatedProjectiles.Add(new GetDataHandlers.ProjectileStruct()
|
player.RecentlyCreatedProjectiles.Add(new GetDataHandlers.ProjectileStruct()
|
||||||
{
|
{
|
||||||
Index = e.number,
|
Index = e.number,
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ProjectExtensions>
|
<ProjectExtensions>
|
||||||
<VisualStudio>
|
<VisualStudio>
|
||||||
<UserProperties BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" BuildVersion_BuildAction="Both" BuildVersion_BuildVersioningStyle="None.None.None.MonthAndDayStamp" BuildVersion_StartDate="2011/6/17" BuildVersion_IncrementBeforeBuild="False" />
|
<UserProperties BuildVersion_IncrementBeforeBuild="False" BuildVersion_StartDate="2011/6/17" BuildVersion_BuildVersioningStyle="None.None.None.MonthAndDayStamp" BuildVersion_BuildAction="Both" BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" />
|
||||||
</VisualStudio>
|
</VisualStudio>
|
||||||
</ProjectExtensions>
|
</ProjectExtensions>
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
|
|
||||||
|
|
@ -531,6 +531,11 @@ namespace TShockAPI
|
||||||
{
|
{
|
||||||
seconds = 0;
|
seconds = 0;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(str))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var sb = new StringBuilder(3);
|
var sb = new StringBuilder(3);
|
||||||
for (int i = 0; i < str.Length; i++)
|
for (int i = 0; i < str.Length; i++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue