From d50ec7ac66707239398cb2439af0e5615e43dec3 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sat, 24 May 2025 23:47:41 +0200 Subject: [PATCH 01/17] feat: implement IP whitelist management service Introduces a class for managing a whitelist of IP addresses and networks, enabling adding, removing, and persisting entries to a file. Whitelist is used to allow or restrict access based on IP, with support for CIDR networks and individual IPs. --- TShockAPI/Whitelist.cs | 245 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 TShockAPI/Whitelist.cs diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs new file mode 100644 index 000000000..2900c805e --- /dev/null +++ b/TShockAPI/Whitelist.cs @@ -0,0 +1,245 @@ +/* +TShock, a server mod for Terraria +Copyright (C) 2011-2025 Pryaxis & TShock Contributors + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using TShockAPI.Configuration; + +namespace TShockAPI; + +/// +/// Provides the storage for a whitelist. +/// +public sealed class Whitelist +{ + private readonly FileInfo _file; + private readonly Lock _fileLock = new(); + + private readonly HashSet _whitelistAddresses = []; + private readonly HashSet _whitelistNetworks = []; + + /// + /// Defines if the whitelist is enabled or not. + /// + /// Shorthand to the current setting. + private bool Enabled => TShock.Config.Settings.EnableWhitelist; + + private const string DefaultWhitelistContent = /*lang=conf*/ + """ + # Localhost + 127.0.0.1 + ::1 + + # Uncomment to allow all IPs in your home network + # 192.168.0.0/24 + """; + + private const char CommentPrefix = '#'; + + /// + /// Initializes a new instance of the class. + /// Creates the whitelist file if it does not exist on disk. + /// + public Whitelist(string path) + { + _file = new(path); + FileTools.CreateIfNot(_file.FullName, DefaultWhitelistContent); + ReadWhitelistFromFile(); + } + + /// + /// Tells if a user is on the whitelist + /// + /// string ip of the user + /// true/false + public bool IsWhitelisted(string host) + { + if (!Enabled) + { + return true; + } + + if (!IPAddress.TryParse(TShock.Utils.GetRealIP(host), out IPAddress? ip)) + { + throw new ArgumentException($"The provided host '{host}' is not a valid IP address.", nameof(host)); + } + + // First check if the IP address is directly whitelisted + return _whitelistAddresses.Contains(ip) + // Otherwise is it contained within a whitelisted network? + || _whitelistNetworks.Any(n => n.Contains(ip)); + } + + private void ReadWhitelistFromFile() + { + using StreamReader sr = _file.OpenText(); + + int i = 0; + while (!sr.EndOfStream) + { + ReadWhitelistLine(sr.ReadLine(), i); + i++; + } + } + + private void ReadWhitelistLine(scoped ReadOnlySpan content, int line) + { + // Ignore blank line or comment + if (content is [] or [CommentPrefix, ..]) + { + return; + } + + // Try parse first IP range, which uses CIDR sep as discriminator. + if (IPNetwork.TryParse(content, out IPNetwork range)) + { + _whitelistNetworks.Add(range); + } + else if (IPAddress.TryParse(content, out IPAddress? ip)) + { + _whitelistAddresses.Add(ip); + } + else + { + // If we reach here, the line is not a valid IP address or network. + // We could throw this, but for now we just log and ignore it. + TShock.Log.Warn($"Invalid whitelist entry at line {line}: \"{content.ToString()}\", skipped"); + } + } + + /// + /// Adds an IP address or network to the whitelist. + /// + /// The IP address or network to add. + /// true if the address or network was added successfully; otherwise, false. + public bool AddToWhitelist(scoped ReadOnlySpan ip) + { + if (IPNetwork.TryParse(ip, out IPNetwork range)) + { + return AddToWhitelist(range); + } + + if (IPAddress.TryParse(ip, out IPAddress? address)) + { + return AddToWhitelist(address); + } + + return false; + } + + /// + /// Removes an IP address or network from the whitelist. + /// + /// The IP address or network to remove. + /// >true if the address or network was removed successfully; otherwise, false. + public bool RemoveFromWhitelist(scoped ReadOnlySpan ip) + { + if (IPNetwork.TryParse(ip, out IPNetwork range)) + { + return RemoveFromWhitelist(range); + } + + if (IPAddress.TryParse(ip, out IPAddress? address)) + { + return RemoveFromWhitelist(address); + } + + return false; + } + + + private bool AddToWhitelist(IPAddress ip) + => _whitelistAddresses.Add(ip) + && AddLine(ip.ToString()); + + private bool AddToWhitelist(IPNetwork network) + => _whitelistNetworks.Add(network) + && AddLine(network.ToString()); + + private bool RemoveFromWhitelist(IPAddress ip) + => _whitelistAddresses.Remove(ip) + && RemoveLine(ip.ToString()); + + private bool RemoveFromWhitelist(IPNetwork network) + => _whitelistNetworks.Remove(network) + && RemoveLine(network.ToString()); + + private bool AddLine(scoped ReadOnlySpan content) + { + lock (_fileLock) + { + using StreamWriter sw = _file.AppendText(); + sw.WriteLine(content); + return true; + } + } + + + private bool RemoveLine(scoped ReadOnlySpan content) + { + if (content is []) + { + throw new ArgumentException("Content cannot be empty.", nameof(content)); + } + + lock (_fileLock) + { + string tempFile = Path.GetTempFileName(); + + using StreamReader sr = _file.OpenText(); + using StreamWriter sw = new(tempFile); + + bool removed = false; + + while (!sr.EndOfStream) + { + scoped ReadOnlySpan line = sr.ReadLine(); + + // If the line does not match the content, write it to the temp file + if (line != content) + { + sw.WriteLine(line); + } + else + { + removed = true; + } + } + + // If we removed a line, we need to overwrite the original file + if (removed) + { + sw.Flush(); + + _file.Delete(); + File.Move(tempFile, _file.FullName); + } + else + { + File.Delete(tempFile); + } + + return removed; + } + } +} From d2f9ecca590acfee4726e1244c85d7031d587732 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 00:04:29 +0200 Subject: [PATCH 02/17] style: update IP comments for private ranges Clarifies and adds more private IP range options in the whitelist comments for better configuration guidance --- TShockAPI/Whitelist.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs index 2900c805e..671195a77 100644 --- a/TShockAPI/Whitelist.cs +++ b/TShockAPI/Whitelist.cs @@ -50,8 +50,12 @@ public sealed class Whitelist 127.0.0.1 ::1 - # Uncomment to allow all IPs in your home network - # 192.168.0.0/24 + # Uncomment to allow IPs within private ranges + # 10.0.0.0/8 + # 172.16.0.0/12 + # 192.168.0.0/16 + # fe80::/10 + # fd00::/8 """; private const char CommentPrefix = '#'; From 699e5d7d5f7108f49e16eec7b63383a0f74e41ee Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 00:15:21 +0200 Subject: [PATCH 03/17] feat: Use new whitelist system Introduces the whitelist system as a core component and applies it during player IP checks, replacing direct file-based whitelisting calls with a dedicated service to improve clarity and maintainability. --- TShockAPI/TShock.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 99153deb8..cae210663 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -140,6 +140,11 @@ public class TShock : TerrariaPlugin /// The TShock anti-cheat/anti-exploit system. internal Bouncer Bouncer; + /// + /// TShock's whitelist system. + /// + internal Whitelist Whitelist { get; set; } + /// The TShock item ban system. public static ItemBans ItemBans; @@ -354,6 +359,7 @@ public override void Initialize() Bouncer = new Bouncer(); RegionSystem = new RegionHandler(Regions); ItemBans = new ItemBans(this, DB); + Whitelist = new(FileTools.WhitelistPath); var geoippath = "GeoIP.dat"; if (Config.Settings.EnableGeoIP && File.Exists(geoippath)) @@ -1317,7 +1323,7 @@ private void OnConnect(ConnectEventArgs args) return; } - if (!FileTools.OnWhitelist(player.IP)) + if (!Whitelist.IsWhitelisted(player.IP)) { player.Kick(Config.Settings.WhitelistKickReason, true, true, null, false); args.Handled = true; From e8a3ebfed8db56c2fedd062368edcf5f085f971e Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 00:16:10 +0200 Subject: [PATCH 04/17] refactor: Improve default whitelist file creation --- TShockAPI/FileTools.cs | 9 +++------ TShockAPI/Whitelist.cs | 11 ++++++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/TShockAPI/FileTools.cs b/TShockAPI/FileTools.cs index a3d6c1c20..7e2623d51 100644 --- a/TShockAPI/FileTools.cs +++ b/TShockAPI/FileTools.cs @@ -49,10 +49,7 @@ internal static string MotdPath /// /// Path to the file containing the whitelist. /// - internal static string WhitelistPath - { - get { return Path.Combine(TShock.SavePath, "whitelist.txt"); } - } + internal static string WhitelistPath => Path.Combine(TShock.SavePath, "whitelist.txt"); /// /// Path to the file containing the config. @@ -104,8 +101,8 @@ public static void SetupConfig() CreateIfNot(RulesPath, "Respect the admins!\nDon't use TNT!"); CreateIfNot(MotdPath, MotdFormat); - - CreateIfNot(WhitelistPath); + + CreateIfNot(WhitelistPath, Whitelist.DefaultWhitelistContent); bool writeConfig = true; // Default to true if the file doesn't exist if (File.Exists(ConfigPath)) { diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs index 671195a77..8a7929c0c 100644 --- a/TShockAPI/Whitelist.cs +++ b/TShockAPI/Whitelist.cs @@ -44,7 +44,7 @@ public sealed class Whitelist /// Shorthand to the current setting. private bool Enabled => TShock.Config.Settings.EnableWhitelist; - private const string DefaultWhitelistContent = /*lang=conf*/ + internal const string DefaultWhitelistContent = /*lang=conf*/ """ # Localhost 127.0.0.1 @@ -58,7 +58,7 @@ public sealed class Whitelist # fd00::/8 """; - private const char CommentPrefix = '#'; + internal const char CommentPrefix = '#'; /// /// Initializes a new instance of the class. @@ -67,7 +67,12 @@ public sealed class Whitelist public Whitelist(string path) { _file = new(path); - FileTools.CreateIfNot(_file.FullName, DefaultWhitelistContent); + + if (!_file.Exists) + { + throw new FileNotFoundException("The whitelist file does not exist", _file.FullName); + } + ReadWhitelistFromFile(); } From a9fe6c65b2b2997d34ddcd9d86c0940cd93ed81e Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 00:40:00 +0200 Subject: [PATCH 05/17] refactor: move whitelist management to static property --- TShockAPI/TShock.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index cae210663..e683835e7 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -128,6 +128,12 @@ public class TShock : TerrariaPlugin public static ILog Log; /// instance - Static reference to the TerrariaPlugin instance. public static TerrariaPlugin instance; + + /// + /// Whitelist - Static reference to the whitelist system, which allows whitelisting of IP addresses and networks. + /// + public static Whitelist Whitelist { get; set; } + /// /// Static reference to a used for simple command-line parsing /// @@ -140,11 +146,6 @@ public class TShock : TerrariaPlugin /// The TShock anti-cheat/anti-exploit system. internal Bouncer Bouncer; - /// - /// TShock's whitelist system. - /// - internal Whitelist Whitelist { get; set; } - /// The TShock item ban system. public static ItemBans ItemBans; From 933d6409d5f489601c68dac2e782de8a3c96cb18 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 00:40:25 +0200 Subject: [PATCH 06/17] feat: use new whitelist service for add command --- TShockAPI/Commands.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 161834318..480dbb243 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -1742,12 +1742,8 @@ void BanDetails() private static void Whitelist(CommandArgs args) { - if (args.Parameters.Count == 1) + if (args.Parameters is [{ } ip] && TShock.Whitelist.AddToWhitelist(ip)) { - using (var tw = new StreamWriter(FileTools.WhitelistPath, true)) - { - tw.WriteLine(args.Parameters[0]); - } args.Player.SendSuccessMessage(GetString($"Added {args.Parameters[0]} to the whitelist.")); } } From ae82a7e29143197c9c50fb3b6300c93374d6ae26 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 00:40:37 +0200 Subject: [PATCH 07/17] fix: ensure newlines before appending to file Adds logic to check if the file ends with a newline and inserts one if needed to prevent line concatenation issues. --- TShockAPI/Whitelist.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs index 8a7929c0c..8d3cffdf3 100644 --- a/TShockAPI/Whitelist.cs +++ b/TShockAPI/Whitelist.cs @@ -197,7 +197,23 @@ private bool AddLine(scoped ReadOnlySpan content) { lock (_fileLock) { + using StreamWriter sw = _file.AppendText(); + + // Case: File does not end with a newline, add one + bool needsNewLine; + + using (FileStream fs = _file.OpenRead()) + { + fs.Seek(-1, SeekOrigin.End); + needsNewLine = fs.Length > 0 && fs.ReadByte() != '\n'; + } + + if (needsNewLine) + { + sw.WriteLine(); + } + sw.WriteLine(content); return true; } From 9e1991c3f162cc6d751f412e19e5bf20e75af8d2 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 00:56:30 +0200 Subject: [PATCH 08/17] chore: Remove old whitelist check code --- TShockAPI/FileTools.cs | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/TShockAPI/FileTools.cs b/TShockAPI/FileTools.cs index 7e2623d51..5fe6ea1e3 100644 --- a/TShockAPI/FileTools.cs +++ b/TShockAPI/FileTools.cs @@ -137,39 +137,6 @@ public static void SetupConfig() } } - /// - /// Tells if a user is on the whitelist - /// - /// string ip of the user - /// true/false - public static bool OnWhitelist(string ip) - { - if (!TShock.Config.Settings.EnableWhitelist) - { - return true; - } - CreateIfNot(WhitelistPath, "127.0.0.1"); - using (var tr = new StreamReader(WhitelistPath)) - { - string whitelist = tr.ReadToEnd(); - ip = TShock.Utils.GetRealIP(ip); - bool contains = whitelist.Contains(ip); - if (!contains) - { - foreach (var line in whitelist.Split(Environment.NewLine.ToCharArray())) - { - if (string.IsNullOrWhiteSpace(line)) - continue; - contains = TShock.Utils.GetIPv4AddressFromHostname(line).Equals(ip); - if (contains) - return true; - } - return false; - } - return true; - } - } - /// /// Looks for a 'Settings' token in the json object. If one is not found, returns a new json object with all tokens of the previous object added /// as children to a root 'Settings' token From 00dbbc0c95b192727d36ab9f9f24e79238558d23 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 11:29:06 +0200 Subject: [PATCH 09/17] style: Fix indentations and newlines --- TShockAPI/Whitelist.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs index 8d3cffdf3..fe12c39a1 100644 --- a/TShockAPI/Whitelist.cs +++ b/TShockAPI/Whitelist.cs @@ -15,6 +15,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the You should have received a copy of the GNU General Public License along with this program. If not, see . */ + #nullable enable using System; @@ -197,7 +198,6 @@ private bool AddLine(scoped ReadOnlySpan content) { lock (_fileLock) { - using StreamWriter sw = _file.AppendText(); // Case: File does not end with a newline, add one @@ -264,7 +264,7 @@ private bool RemoveLine(scoped ReadOnlySpan content) File.Delete(tempFile); } - return removed; + return removed; } } } From cc0fd66972eab58fe170d3a5cb476bc7d5f28f04 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 11:37:02 +0200 Subject: [PATCH 10/17] refactor: Improve whitelist command validation and feedback Enhances the whitelist command to correctly handle parameter input, provides success or error messages based on the addition outcome. --- TShockAPI/Commands.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 480dbb243..84e7ab5a7 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -1742,9 +1742,20 @@ void BanDetails() private static void Whitelist(CommandArgs args) { - if (args.Parameters is [{ } ip] && TShock.Whitelist.AddToWhitelist(ip)) + if (args.Parameters is [{ } ip]) { - args.Player.SendSuccessMessage(GetString($"Added {args.Parameters[0]} to the whitelist.")); + if (TShock.Whitelist.AddToWhitelist(ip)) + { + args.Player.SendSuccessMessage(GetString($"Added {ip} to the whitelist.")); + } + else + { + args.Player.SendErrorMessage(GetString($"Failed to add {ip} to the whitelist. Perhaps it is already whitelisted?")); + } + } + else + { + args.Player.SendErrorMessage(GetString($"Invalid Whitelist syntax. Refer to {Specifier}whitelist help for details on how to use the {Specifier}whitelist command")); } } From e8ac543797822f556905fdcc6cd58ec14a3ff84f Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 11:49:51 +0200 Subject: [PATCH 11/17] fix: Remove IPv6 whitelist support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forgot to check if Terraria itself actually DOES support IPv6... According to a few researches, latest hotfixes have grazed the subject. Hopefully we'll get IPv6 soon 🤞🏻 --- .idea/.idea.TShock/.idea/.gitignore | 13 +++++++++++++ .idea/.idea.TShock/.idea/dataSources.xml | 15 +++++++++++++++ .idea/.idea.TShock/.idea/indexLayout.xml | 8 ++++++++ .idea/.idea.TShock/.idea/vcs.xml | 7 +++++++ TShockAPI/Whitelist.cs | 16 ++++++++++++---- 5 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 .idea/.idea.TShock/.idea/.gitignore create mode 100644 .idea/.idea.TShock/.idea/dataSources.xml create mode 100644 .idea/.idea.TShock/.idea/indexLayout.xml create mode 100644 .idea/.idea.TShock/.idea/vcs.xml diff --git a/.idea/.idea.TShock/.idea/.gitignore b/.idea/.idea.TShock/.idea/.gitignore new file mode 100644 index 000000000..40bf43173 --- /dev/null +++ b/.idea/.idea.TShock/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.TShock.iml +/modules.xml +/contentModel.xml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.TShock/.idea/dataSources.xml b/.idea/.idea.TShock/.idea/dataSources.xml new file mode 100644 index 000000000..e5ab519f3 --- /dev/null +++ b/.idea/.idea.TShock/.idea/dataSources.xml @@ -0,0 +1,15 @@ + + + + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:$PROJECT_DIR$/TShockLauncher/bin/Debug/net6.0/tshock/tshock.sqlite + + + + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/.idea.TShock/.idea/indexLayout.xml b/.idea/.idea.TShock/.idea/indexLayout.xml new file mode 100644 index 000000000..7b08163ce --- /dev/null +++ b/.idea/.idea.TShock/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.TShock/.idea/vcs.xml b/.idea/.idea.TShock/.idea/vcs.xml new file mode 100644 index 000000000..2984bb1ba --- /dev/null +++ b/.idea/.idea.TShock/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs index fe12c39a1..705dac2a8 100644 --- a/TShockAPI/Whitelist.cs +++ b/TShockAPI/Whitelist.cs @@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License using System.IO; using System.Linq; using System.Net; +using System.Net.Sockets; using System.Threading; using TShockAPI.Configuration; @@ -49,14 +50,11 @@ public sealed class Whitelist """ # Localhost 127.0.0.1 - ::1 # Uncomment to allow IPs within private ranges # 10.0.0.0/8 # 172.16.0.0/12 # 192.168.0.0/16 - # fe80::/10 - # fd00::/8 """; internal const char CommentPrefix = '#'; @@ -89,11 +87,21 @@ public bool IsWhitelisted(string host) return true; } - if (!IPAddress.TryParse(TShock.Utils.GetRealIP(host), out IPAddress? ip)) + if (!IPAddress.TryParse(host, out IPAddress? ip)) { throw new ArgumentException($"The provided host '{host}' is not a valid IP address.", nameof(host)); } + // HACK: Terraria doesn't support IPv6 yet, so we can't check for it. + // Remove once TShock supports IPv6. + if (ip.AddressFamily is AddressFamily.InterNetworkV6) + { + TShock.Log.Warn($"IPv6 address '{ip}' is not supported by Terraria. Skipping check."); + TShock.Log.Warn("If you somehow managed to get this message, please report it to the TShock team :"); + TShock.Log.Warn("https://github.com/Pryaxis/TShock/issues"); + return false; + } + // First check if the IP address is directly whitelisted return _whitelistAddresses.Contains(ip) // Otherwise is it contained within a whitelisted network? From bd2497f4a6820d3fa047b67af15f6e9895243088 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 15:23:19 +0200 Subject: [PATCH 12/17] feat: Add whitelist reload functionality Introduces a method to reload whitelist data from file, allowing updates without restarting the server. --- TShockAPI/Utils.cs | 1 + TShockAPI/Whitelist.cs | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 613e7a8a4..f10a68bb9 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -607,6 +607,7 @@ public void Reload() TShock.ItemBans.DataModel.UpdateItemBans(); TShock.ProjectileBans.UpdateBans(); TShock.TileBans.UpdateBans(); + TShock.Whitelist.ReloadFromFile(); } /// diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs index 705dac2a8..eef5231a8 100644 --- a/TShockAPI/Whitelist.cs +++ b/TShockAPI/Whitelist.cs @@ -108,6 +108,19 @@ public bool IsWhitelisted(string host) || _whitelistNetworks.Any(n => n.Contains(ip)); } + /// + /// Reloads the whitelist from the file. + /// + public void ReloadFromFile() + { + lock (_fileLock) + { + _whitelistAddresses.Clear(); + _whitelistNetworks.Clear(); + ReadWhitelistFromFile(); + } + } + private void ReadWhitelistFromFile() { using StreamReader sr = _file.OpenText(); @@ -123,7 +136,7 @@ private void ReadWhitelistFromFile() private void ReadWhitelistLine(scoped ReadOnlySpan content, int line) { // Ignore blank line or comment - if (content is [] or [CommentPrefix, ..]) + if (content is [] or [CommentPrefix, ..] || content.IsWhiteSpace()) { return; } From 3a18dab9b7a0724a8b33e38ea9c689f4c60a652e Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 17:20:43 +0200 Subject: [PATCH 13/17] fix: Fix unwanted changes Oops, should've paid more attention ^^' --- .gitignore | 2 ++ .idea/.idea.TShock/.idea/.gitignore | 13 ------------- .idea/.idea.TShock/.idea/dataSources.xml | 15 --------------- .idea/.idea.TShock/.idea/indexLayout.xml | 8 -------- .idea/.idea.TShock/.idea/vcs.xml | 7 ------- TerrariaServerAPI | 2 +- 6 files changed, 3 insertions(+), 44 deletions(-) delete mode 100644 .idea/.idea.TShock/.idea/.gitignore delete mode 100644 .idea/.idea.TShock/.idea/dataSources.xml delete mode 100644 .idea/.idea.TShock/.idea/indexLayout.xml delete mode 100644 .idea/.idea.TShock/.idea/vcs.xml diff --git a/.gitignore b/.gitignore index 5ac4b6aad..b86d68654 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,5 @@ packages/* # Private key files # scripts/ssh_private_key + +.idea/ diff --git a/.idea/.idea.TShock/.idea/.gitignore b/.idea/.idea.TShock/.idea/.gitignore deleted file mode 100644 index 40bf43173..000000000 --- a/.idea/.idea.TShock/.idea/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Rider ignored files -/.idea.TShock.iml -/modules.xml -/contentModel.xml -/projectSettingsUpdater.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/.idea.TShock/.idea/dataSources.xml b/.idea/.idea.TShock/.idea/dataSources.xml deleted file mode 100644 index e5ab519f3..000000000 --- a/.idea/.idea.TShock/.idea/dataSources.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - sqlite.xerial - true - org.sqlite.JDBC - jdbc:sqlite:$PROJECT_DIR$/TShockLauncher/bin/Debug/net6.0/tshock/tshock.sqlite - - - - $ProjectFileDir$ - - - \ No newline at end of file diff --git a/.idea/.idea.TShock/.idea/indexLayout.xml b/.idea/.idea.TShock/.idea/indexLayout.xml deleted file mode 100644 index 7b08163ce..000000000 --- a/.idea/.idea.TShock/.idea/indexLayout.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/.idea.TShock/.idea/vcs.xml b/.idea/.idea.TShock/.idea/vcs.xml deleted file mode 100644 index 2984bb1ba..000000000 --- a/.idea/.idea.TShock/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/TerrariaServerAPI b/TerrariaServerAPI index 9dc782755..2b81ac745 160000 --- a/TerrariaServerAPI +++ b/TerrariaServerAPI @@ -1 +1 @@ -Subproject commit 9dc7827552a144c50012c7d75f50cccc793ec04f +Subproject commit 2b81ac74594d2ca56be9831d31c277201b003257 From c97f960ed09f284f34ca1ae1d086ab08de531ab9 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Sun, 25 May 2025 18:23:30 +0200 Subject: [PATCH 14/17] fix: use bitwise AND instead of logical AND for whitelist updates Switches to bitwise AND operator to correctly combine add/remove operations with line updates. --- TShockAPI/Whitelist.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs index eef5231a8..a1e3c5385 100644 --- a/TShockAPI/Whitelist.cs +++ b/TShockAPI/Whitelist.cs @@ -201,19 +201,19 @@ public bool RemoveFromWhitelist(scoped ReadOnlySpan ip) private bool AddToWhitelist(IPAddress ip) => _whitelistAddresses.Add(ip) - && AddLine(ip.ToString()); + & AddLine(ip.ToString()); private bool AddToWhitelist(IPNetwork network) => _whitelistNetworks.Add(network) - && AddLine(network.ToString()); + & AddLine(network.ToString()); private bool RemoveFromWhitelist(IPAddress ip) => _whitelistAddresses.Remove(ip) - && RemoveLine(ip.ToString()); + & RemoveLine(ip.ToString()); private bool RemoveFromWhitelist(IPNetwork network) => _whitelistNetworks.Remove(network) - && RemoveLine(network.ToString()); + & RemoveLine(network.ToString()); private bool AddLine(scoped ReadOnlySpan content) { From d18b7c106e98efa5b845dba806d7002cb6ed6f43 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Fri, 30 May 2025 16:04:53 +0200 Subject: [PATCH 15/17] fix: Correct fs handling in addline --- TShockAPI/Whitelist.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs index a1e3c5385..01e5feb93 100644 --- a/TShockAPI/Whitelist.cs +++ b/TShockAPI/Whitelist.cs @@ -219,17 +219,17 @@ private bool AddLine(scoped ReadOnlySpan content) { lock (_fileLock) { - using StreamWriter sw = _file.AppendText(); - // Case: File does not end with a newline, add one bool needsNewLine; - using (FileStream fs = _file.OpenRead()) + using (FileStream fs = _file.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { fs.Seek(-1, SeekOrigin.End); - needsNewLine = fs.Length > 0 && fs.ReadByte() != '\n'; + needsNewLine = fs.Length > 0 && fs.ReadByte() is not '\n'; } + using StreamWriter sw = _file.AppendText(); + if (needsNewLine) { sw.WriteLine(); From eb52d11105839f774e2261d4647543a6ec5d224c Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Fri, 30 May 2025 16:40:44 +0200 Subject: [PATCH 16/17] refactor: improve whitelist command handling Add a warning message when IPv6 addresses are used in whitelist commands, as IPv6 support isn't implemented yet, and update error message for better clarity on correct command usage --- TShockAPI/Commands.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 84e7ab5a7..5d94fbe36 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -1744,6 +1744,14 @@ private static void Whitelist(CommandArgs args) { if (args.Parameters is [{ } ip]) { + // Warn if IP addr/net is v6 + if (ip.Contains(':')) + { + args.Player.SendWarningMessage(GetString( + "IPv6 addresses are not supported as of yet by TShock. This rule will have no effect for now. Adding anyways." + )); + } + if (TShock.Whitelist.AddToWhitelist(ip)) { args.Player.SendSuccessMessage(GetString($"Added {ip} to the whitelist.")); @@ -1755,7 +1763,7 @@ private static void Whitelist(CommandArgs args) } else { - args.Player.SendErrorMessage(GetString($"Invalid Whitelist syntax. Refer to {Specifier}whitelist help for details on how to use the {Specifier}whitelist command")); + args.Player.SendErrorMessage(GetString($"Invalid Whitelist syntax. Usage: {Specifier}whitelist ")); } } From b7d8208d57e5ef12d9f314dfc1c68177df3e3d13 Mon Sep 17 00:00:00 2001 From: Sakura Akeno Isayeki Date: Fri, 30 May 2025 16:42:42 +0200 Subject: [PATCH 17/17] fix: localize logging messages for IPv6 support and invalid entries Switches to localized strings for IPv6 warnings and invalid whitelist entry logs. --- TShockAPI/Whitelist.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/TShockAPI/Whitelist.cs b/TShockAPI/Whitelist.cs index 01e5feb93..a53d5d69d 100644 --- a/TShockAPI/Whitelist.cs +++ b/TShockAPI/Whitelist.cs @@ -96,9 +96,10 @@ public bool IsWhitelisted(string host) // Remove once TShock supports IPv6. if (ip.AddressFamily is AddressFamily.InterNetworkV6) { - TShock.Log.Warn($"IPv6 address '{ip}' is not supported by Terraria. Skipping check."); - TShock.Log.Warn("If you somehow managed to get this message, please report it to the TShock team :"); - TShock.Log.Warn("https://github.com/Pryaxis/TShock/issues"); + TShock.Log.Warn(GetString($"IPv6 address '{ip}' is not supported by Terraria. Skipping check.")); + TShock.Log.Warn(GetString("If you somehow managed to get this message, please report it to the TShock team :")); + TShock.Log.Warn(GetString("https://github.com/Pryaxis/TShock/issues")); + return false; } @@ -154,7 +155,7 @@ private void ReadWhitelistLine(scoped ReadOnlySpan content, int line) { // If we reach here, the line is not a valid IP address or network. // We could throw this, but for now we just log and ignore it. - TShock.Log.Warn($"Invalid whitelist entry at line {line}: \"{content.ToString()}\", skipped"); + TShock.Log.Warn(GetString($"Invalid whitelist entry at line {line}: \"{content.ToString()}\", skipped")); } }