diff --git a/CHANGELOG.md b/CHANGELOG.md index fa98e0ca..d66fea41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Fixed butterfly statues spawning catchable butterflies (@DogooFalchion). * Implemented some missing balance changes lost in prior version patches (@DogooFalchion). * Added alias for server shutdown command: stop (@nicatronTg). +* Removed the old REST model. This includes the following endpoints: + * `/status` + * `/v2/players/read` + * `/v2/server/rawcmd` (@WhiteXZ). ## TShock 4.3.20 * Security improvement: The auth system is now automatically disabled if a superadmin exists in the database (@Enerdy). diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index c0227d05..2d2d26d2 100755 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -443,10 +443,6 @@ namespace TShockAPI [Description("#.#.# = Red/Blue/Green - RGB Colors for broadcasts. Max value: 255.")] public int[] BroadcastRGB = { 127, 255, 212 }; - // TODO: Get rid of this when the old REST permission model is removed. - [Description("Whether the REST API should use the new permission model. Note: The old permission model will become depracted in the future.")] - public bool RestUseNewPermissionModel = true; - /// ApplicationRestTokens - A dictionary of REST tokens that external applications may use to make queries to your server. [Description("A dictionary of REST tokens that external applications may use to make queries to your server.")] public Dictionary ApplicationRestTokens = new Dictionary(); diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs index d74aa6c5..d16e17f6 100644 --- a/TShockAPI/Rest/RestManager.cs +++ b/TShockAPI/Rest/RestManager.cs @@ -103,14 +103,12 @@ namespace TShockAPI if (TShock.Config.EnableTokenEndpointAuthentication) { Rest.Register(new SecureRestCommand("/v2/server/status", ServerStatusV2)); - Rest.Register(new SecureRestCommand("/status", ServerStatus)); Rest.Register(new SecureRestCommand("/v3/server/motd", ServerMotd)); Rest.Register(new SecureRestCommand("/v3/server/rules", ServerRules)); } else { Rest.Register(new RestCommand("/v2/server/status", (a) => this.ServerStatusV2(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None, a.Context)))); - Rest.Register(new RestCommand("/status", (a) => this.ServerStatus(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None, a.Context)))); Rest.Register(new RestCommand("/v3/server/motd", (a) => this.ServerMotd(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None, a.Context)))); Rest.Register(new RestCommand("/v3/server/rules", (a) => this.ServerRules(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None, a.Context)))); } @@ -119,7 +117,6 @@ namespace TShockAPI Rest.Register(new SecureRestCommand("/v3/server/reload", ServerReload, RestPermissions.restcfg)); Rest.Register(new SecureRestCommand("/v2/server/off", ServerOff, RestPermissions.restmaintenance)); Rest.Register(new SecureRestCommand("/v3/server/restart", ServerRestart, RestPermissions.restmaintenance)); - Rest.Register(new SecureRestCommand("/v2/server/rawcmd", ServerCommand, RestPermissions.restrawcommand)); Rest.Register(new SecureRestCommand("/v3/server/rawcmd", ServerCommandV3, RestPermissions.restrawcommand)); Rest.Register(new SecureRestCommand("/tokentest", ServerTokenTest)); @@ -148,7 +145,6 @@ namespace TShockAPI // Player Commands Rest.Register(new SecureRestCommand("/lists/players", PlayerList)); Rest.Register(new SecureRestCommand("/v2/players/list", PlayerListV2)); - Rest.Register(new SecureRestCommand("/v2/players/read", PlayerReadV2, RestPermissions.restuserinfo)); Rest.Register(new SecureRestCommand("/v3/players/read", PlayerReadV3, RestPermissions.restuserinfo)); Rest.Register(new SecureRestCommand("/v2/players/kick", PlayerKickV2, RestPermissions.restkick)); Rest.Register(new SecureRestCommand("/v2/players/ban", PlayerBanV2, RestPermissions.restban, RestPermissions.restmanagebans)); @@ -166,28 +162,6 @@ namespace TShockAPI #region RestServerMethods - [Description("Executes a remote command on the server, and returns the output of the command.")] - [RouteAttribute("/v2/server/rawcmd")] - [Permission(RestPermissions.restrawcommand)] - [Noun("cmd", true, "The command and arguments to execute.", typeof(String))] - [Token] - private object ServerCommand(RestRequestArgs args) - { - if (string.IsNullOrWhiteSpace(args.Parameters["cmd"])) - return RestMissingParam("cmd"); - - Group restPlayerGroup; - // TODO: Get rid of this when the old REST permission model is removed. - if (TShock.Config.RestUseNewPermissionModel) - restPlayerGroup = TShock.Groups.GetGroupByName(args.TokenData.UserGroupName); - else - restPlayerGroup = new SuperAdminGroup(); - - TSRestPlayer tr = new TSRestPlayer(args.TokenData.Username, restPlayerGroup); - Commands.HandleCommand(tr, args.Parameters["cmd"]); - return RestResponse(string.Join("\n", tr.GetCommandOutput())); - } - [Description("Executes a remote command on the server, and returns the output of the command.")] [RouteAttribute("/v3/server/rawcmd")] [Permission(RestPermissions.restrawcommand)] @@ -198,12 +172,7 @@ namespace TShockAPI if (string.IsNullOrWhiteSpace(args.Parameters["cmd"])) return RestMissingParam("cmd"); - Group restPlayerGroup; - // TODO: Get rid of this when the old REST permission model is removed. - if (TShock.Config.RestUseNewPermissionModel) - restPlayerGroup = TShock.Groups.GetGroupByName(args.TokenData.UserGroupName); - else - restPlayerGroup = new SuperAdminGroup(); + Group restPlayerGroup = TShock.Groups.GetGroupByName(args.TokenData.UserGroupName); TSRestPlayer tr = new TSRestPlayer(args.TokenData.Username, restPlayerGroup); Commands.HandleCommand(tr, args.Parameters["cmd"]); @@ -305,21 +274,6 @@ namespace TShockAPI }; } - [Description("Returns the current status of the server.")] - [Route("/status")] - [Token] - private object ServerStatus(RestRequestArgs args) - { - var activeplayers = Main.player.Where(p => null != p && p.active).ToList(); - return new RestObject() - { - {"name", TShock.Config.ServerName}, - {"port", Convert.ToString(Netplay.ListenPort)}, - {"playercount", Convert.ToString(activeplayers.Count())}, - {"players", string.Join(", ", activeplayers.Select(p => p.name))}, - }; - } - [Description("Get a list of information about the current TShock server.")] [Route("/v2/server/status")] [Token] @@ -791,32 +745,6 @@ namespace TShockAPI return new RestObject() { { "players", playerList } }; } - [Description("Get information for a user.")] - [Route("/v2/players/read")] - [Permission(RestPermissions.restuserinfo)] - [Noun("player", true, "The player to lookup", typeof(String))] - [Token] - private object PlayerReadV2(RestRequestArgs args) - { - var ret = PlayerFind(args.Parameters); - if (ret is RestObject) - return ret; - - TSPlayer player = (TSPlayer)ret; - var activeItems = player.TPlayer.inventory.Where(p => p.active).ToList(); - return new RestObject() - { - {"nickname", player.Name}, - {"username", null == player.User ? "" : player.User.Name}, - {"ip", player.IP}, - {"group", player.Group.Name}, - {"registered", null == player.User ? "" : player.User.Registered}, - {"position", player.TileX + "," + player.TileY}, - {"inventory", string.Join(", ", activeItems.Select(p => (p.name + ":" + p.stack)))}, - {"buffs", string.Join(", ", player.TPlayer.buffType)} - }; - } - [Description("Get information for a user.")] [Route("/v3/players/read")] [Permission(RestPermissions.restuserinfo)] diff --git a/TShockAPI/Rest/SecureRest.cs b/TShockAPI/Rest/SecureRest.cs index f8290784..cf3a9fd2 100644 --- a/TShockAPI/Rest/SecureRest.cs +++ b/TShockAPI/Rest/SecureRest.cs @@ -44,12 +44,12 @@ namespace Rests { Tokens = new Dictionary(); AppTokens = new Dictionary(); - + Register(new RestCommand("/v2/token/create", NewTokenV2) { DoLog = false }); Register(new SecureRestCommand("/token/destroy/{token}", DestroyToken)); Register(new SecureRestCommand("/v3/token/destroy/all", DestroyAllTokens, RestPermissions.restmanage)); - foreach (KeyValuePair t in TShockAPI.TShock.RESTStartupTokens) + foreach (KeyValuePair t in TShock.RESTStartupTokens) { AppTokens.Add(t.Key, t.Value); } @@ -58,29 +58,6 @@ namespace Rests { AppTokens.Add(t.Key, t.Value); } - - // TODO: Get rid of this when the old REST permission model is removed. - if (TShock.Config.RestApiEnabled && !TShock.Config.RestUseNewPermissionModel) - { - string warningMessage = string.Concat( - "You're using the old REST permission model which is highly vulnerable in matter of security. ", - "The old model will be removed with the next maintenance release of TShock. In order to switch to the new model, ", - "change the config setting \"RestUseNewPermissionModel\" to true." - ); - TShock.Log.Warn(warningMessage); - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(warningMessage); - Console.ForegroundColor = ConsoleColor.Gray; - } - else if (TShock.Config.RestApiEnabled) - { - string warningMessage = string.Concat( - "You're using the new more secure REST permission model which can lead to compatibility problems ", - "with existing REST services. If compatibility problems occur, you can switch back to the unsecure permission ", - "model by changing the config setting \"RestUseNewPermissionModel\" to false, which is not recommended." - ); - TShock.Log.ConsoleInfo(warningMessage); - } } private void AddTokenToBucket(string ip) @@ -206,23 +183,19 @@ namespace Rests return new RestObject("403") { Error = "Not authorized. The specified API endpoint requires a token, but the provided token was not valid." }; - // TODO: Get rid of this when the old REST permission model is removed. - if (TShock.Config.RestUseNewPermissionModel) + Group userGroup = TShock.Groups.GetGroupByName(tokenData.UserGroupName); + if (userGroup == null) { - Group userGroup = TShock.Groups.GetGroupByName(tokenData.UserGroupName); - if (userGroup == null) - { - Tokens.Remove(token); + Tokens.Remove(token); - return new RestObject("403") - { Error = "Not authorized. The provided token became invalid due to group changes, please create a new token." }; - } + return new RestObject("403") + { Error = "Not authorized. The provided token became invalid due to group changes, please create a new token." }; + } - if (secureCmd.Permissions.Length > 0 && secureCmd.Permissions.All(perm => !userGroup.HasPermission(perm))) - { - return new RestObject("403") - { Error = string.Format("Not authorized. User \"{0}\" has no access to use the specified API endpoint.", tokenData.Username) }; - } + if (secureCmd.Permissions.Length > 0 && secureCmd.Permissions.All(perm => !userGroup.HasPermission(perm))) + { + return new RestObject("403") + { Error = string.Format("Not authorized. User \"{0}\" has no access to use the specified API endpoint.", tokenData.Username) }; } object result = secureCmd.Execute(verbs, parms, tokenData, request, context);