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);