From 51f179f84a123b4938d7d8523606d00ac49952a0 Mon Sep 17 00:00:00 2001 From: Chris <2648373+QuiCM@users.noreply.github.com> Date: Wed, 23 Dec 2020 01:46:42 +1030 Subject: [PATCH] Added URI-unescaping for inputs into REST requests --- TShockAPI/Rest/Rest.cs | 96 ++++++++++++++++++++++++++++++++--- TShockAPI/Rest/RestManager.cs | 12 ++--- TShockAPI/Rest/RestVerbs.cs | 9 +++- TShockAPI/Rest/SecureRest.cs | 4 +- 4 files changed, 105 insertions(+), 16 deletions(-) diff --git a/TShockAPI/Rest/Rest.cs b/TShockAPI/Rest/Rest.cs index 214b29ca..51d783f5 100644 --- a/TShockAPI/Rest/Rest.cs +++ b/TShockAPI/Rest/Rest.cs @@ -29,9 +29,84 @@ using HttpServer.Headers; using Newtonsoft.Json; using TShockAPI; using HttpListener = HttpServer.HttpListener; +using System.Collections; namespace Rests { + /// + /// Wraps an , providing URI-unescaping for its value + /// + public class EscapedParameter + { + private IParameter _parameter; + + /// + /// Name of the parameter + /// + public string Name => _parameter.Name; + /// + /// URI-unescaped value of the parameter + /// + public string Value => Uri.UnescapeDataString(_parameter.Value); + + /// + /// Constructs a new EscapedParameter wrapping the given + /// + /// + public EscapedParameter(IParameter parameter) + { + _parameter = parameter; + } + } + + /// + /// Wraps an , providing URI-unescaping for the parameters in the collection + /// + public class EscapedParameterCollection : IEnumerable + { + private readonly IParameterCollection _collection; + + /// + /// Retrieve a parameter by name, returning the URI-unescaped value + /// + /// + /// + public string this[string key] + { + get + { + string value = _collection[key]; + return value == null ? value : Uri.UnescapeDataString(value); + } + } + + /// + /// Constructs a new EscapedParameterCollection wrapping the given + /// + /// + public EscapedParameterCollection(IParameterCollection collection) + { + _collection = collection; + } + + /// + /// Returns an enumerator that can be used to iterate over this collection + /// + /// + public IEnumerator GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + foreach (IParameter param in _collection) + { + yield return new EscapedParameter(param); + } + } + } + /// /// Rest command delegate /// @@ -51,7 +126,7 @@ namespace Rests /// /// Parameters sent in the request /// - public IParameterCollection Parameters { get; private set; } + public EscapedParameterCollection Parameters { get; private set; } /// /// The HTTP request /// @@ -74,12 +149,8 @@ namespace Rests /// The HTTP request /// The HTTP context public RestRequestArgs(RestVerbs verbs, IParameterCollection param, IRequest request, IHttpContext context) + : this(verbs, param, request, SecureRest.TokenData.None, context) { - Verbs = verbs; - Parameters = param; - Request = request; - TokenData = SecureRest.TokenData.None; - Context = context; } /// @@ -91,6 +162,19 @@ namespace Rests /// Token data used in the request /// The HTTP context public RestRequestArgs(RestVerbs verbs, IParameterCollection param, IRequest request, SecureRest.TokenData tokenData, IHttpContext context) + : this(verbs, new EscapedParameterCollection(param), request, tokenData, context) + { + } + + /// + /// Creates a new instance of with the given verbs, escaped parameters, request, token data, and context. + /// + /// + /// + /// + /// + /// + public RestRequestArgs(RestVerbs verbs, EscapedParameterCollection param, IRequest request, SecureRest.TokenData tokenData, IHttpContext context) { Verbs = verbs; Parameters = param; diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs index c93f8907..ce0a4328 100644 --- a/TShockAPI/Rest/RestManager.cs +++ b/TShockAPI/Rest/RestManager.cs @@ -1261,7 +1261,7 @@ namespace TShockAPI return bool.TryParse(val, out ret) ? ret : def; } - private object PlayerFind(IParameterCollection parameters) + private object PlayerFind(EscapedParameterCollection parameters) { string name = parameters["player"]; if (string.IsNullOrWhiteSpace(name)) @@ -1279,7 +1279,7 @@ namespace TShockAPI } } - private object UserFind(IParameterCollection parameters) + private object UserFind(EscapedParameterCollection parameters) { string name = parameters["user"]; if (string.IsNullOrWhiteSpace(name)) @@ -1314,7 +1314,7 @@ namespace TShockAPI return account; } - private object GroupFind(IParameterCollection parameters) + private object GroupFind(EscapedParameterCollection parameters) { var name = parameters["group"]; if (string.IsNullOrWhiteSpace(name)) @@ -1327,7 +1327,7 @@ namespace TShockAPI return group; } - private Dictionary PlayerFilter(TSPlayer tsPlayer, IParameterCollection parameters, bool viewips = false) + private Dictionary PlayerFilter(TSPlayer tsPlayer, EscapedParameterCollection parameters, bool viewips = false) { var player = new Dictionary { @@ -1343,7 +1343,7 @@ namespace TShockAPI { player.Add("ip", tsPlayer.IP); } - foreach (IParameter filter in parameters) + foreach (EscapedParameter filter in parameters) { if (player.ContainsKey(filter.Name) && !player[filter.Name].Equals(filter.Value)) return null; @@ -1351,7 +1351,7 @@ namespace TShockAPI return player; } - private object PlayerSetMute(IParameterCollection parameters, bool mute) + private object PlayerSetMute(EscapedParameterCollection parameters, bool mute) { var ret = PlayerFind(parameters); if (ret is RestObject) diff --git a/TShockAPI/Rest/RestVerbs.cs b/TShockAPI/Rest/RestVerbs.cs index 2de0295b..1ef4addf 100644 --- a/TShockAPI/Rest/RestVerbs.cs +++ b/TShockAPI/Rest/RestVerbs.cs @@ -21,6 +21,9 @@ using System.Collections.Generic; namespace Rests { + /// + /// A dictionary collection of verbs used in a REST request + /// [Serializable] public class RestVerbs : Dictionary { @@ -35,7 +38,9 @@ namespace Rests { string ret; if (TryGetValue(key, out ret)) - return ret; + { + return Uri.UnescapeDataString(ret); + } return null; } set @@ -56,4 +61,4 @@ namespace Rests } } } -} \ No newline at end of file +} diff --git a/TShockAPI/Rest/SecureRest.cs b/TShockAPI/Rest/SecureRest.cs index a88aa764..b9b50919 100644 --- a/TShockAPI/Rest/SecureRest.cs +++ b/TShockAPI/Rest/SecureRest.cs @@ -103,8 +103,8 @@ namespace Rests private object NewTokenV2(RestRequestArgs args) { - var user = args.Parameters["username"]; - var pass = args.Parameters["password"]; + var user = Uri.UnescapeDataString(args.Parameters["username"]); + var pass = Uri.UnescapeDataString(args.Parameters["password"]); var context = args.Context; return this.NewTokenInternal(user, pass, context);