diff --git a/TShockAPI/Rest.cs b/TShockAPI/Rest.cs index c5b54cc8..7a98b7a6 100644 --- a/TShockAPI/Rest.cs +++ b/TShockAPI/Rest.cs @@ -52,10 +52,15 @@ namespace TShockAPI public void Register(string path, RestCommandD callback) { - Register(new RestCommand(path, callback)); + AddCommand(new RestCommand(path, callback)); } - public virtual void Register(RestCommand com) + public void Register(RestCommand com) + { + AddCommand(com); + } + + protected void AddCommand(RestCommand com) { commands.Add(com); } @@ -65,6 +70,7 @@ namespace TShockAPI var obj = ProcessRequest(sender, e); if (obj == null) throw new NullReferenceException("obj"); + var str = JsonConvert.SerializeObject(obj, Formatting.Indented); e.Response.Connection.Type = ConnectionType.Close; e.Response.Body.Write(Encoding.ASCII.GetBytes(str), 0, str.Length); @@ -136,6 +142,64 @@ namespace TShockAPI } + public class RestObject : Dictionary + { + public string Status + { + get { return SafeGet("status"); } + set { SafeSet("status", value); } + } + public string Error + { + get { return SafeGet("error"); } + set { SafeSet("error", value); } + } + + public RestObject(string status) + { + Status = status; + } + public RestObject(string status, string error) + : this(status) + { + Error = error; + } + + /// + /// Gets value safely. + /// + /// + /// Returns null if key does not exist. + public string SafeGet(string key) + { + string ret; + if (TryGetValue(key, out ret)) + return ret; + return null; + } + /// + /// Sets/Adds value safely. If null it will remove. + /// + /// + /// + public void SafeSet(string key, string value) + { + if (!ContainsKey(key)) + { + if (value == null) + return; + Add(key, value); + } + else + { + if (value != null) + this[key] = value; + else + Remove(key); + } + } + } + public class RestCommand { public string Name { get; protected set; } diff --git a/TShockAPI/SecureRest.cs b/TShockAPI/SecureRest.cs index 62df7254..8aff3c48 100644 --- a/TShockAPI/SecureRest.cs +++ b/TShockAPI/SecureRest.cs @@ -7,7 +7,13 @@ using HttpServer; namespace TShockAPI { - public delegate bool VerifyD(string username, string password); + /// + /// + /// + /// Username to verify + /// Password to verify + /// Returning a restobject with a null error means a successful verification. + public delegate RestObject VerifyD(string username, string password); public class SecureRest : Rest { public Dictionary Tokens { get; protected set; } @@ -39,26 +45,17 @@ namespace TShockAPI var user = verbs["username"]; var pass = verbs["password"]; - if (Verify != null && !Verify(user, pass)) - return new Dictionary { { "status", "401" } , { "error", "Invalid username/password combination provided. Please re-submit your query with a correct pair." } }; + RestObject obj = null; + if (Verify != null) + obj = Verify(user, pass); - var userAccount = TShock.Users.GetUserByName(user); - if (userAccount == null) - { - return new Dictionary { { "status", "401" }, { "error", "Invalid username/password combination provided. Please re-submit your query with a correct pair." } }; - } + if (obj == null) + obj = new RestObject("401", "Invalid username/password combination provided. Please re-submit your query with a correct pair."); - if (Tools.HashPassword(pass).ToUpper() != userAccount.Password.ToUpper()) - { - return new Dictionary { { "status", "401" }, { "error", "Invalid username/password combination provided. Please re-submit your query with a correct pair." } }; - } + if (obj.Error != null) + return obj; - if (!Tools.GetGroup(userAccount.Group).HasPermission("api") && userAccount.Group != "superadmin") - { - return new Dictionary { { "status", "403" }, { "error", "Although your account was successfully found and identified, your account lacks the permission required to use the API. (api)" } }; - } - - string hash = string.Empty; + string hash; var rand = new Random(); var randbytes = new byte[20]; do @@ -69,7 +66,8 @@ namespace TShockAPI Tokens.Add(hash, user); - return new Dictionary { { "status", "200" } , { "token", hash } }; ; + obj.SafeSet("token", hash); + return obj; } protected override object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms) diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 555f17b6..7f69c9ee 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -69,7 +69,7 @@ namespace TShockAPI public static bool OverridePort; public static PacketBufferer PacketBuffer; public static MaxMind.GeoIPCountry Geo; - public static Rest RestApi; + public static SecureRest RestApi; public static RestManager RestManager; /// @@ -177,6 +177,7 @@ namespace TShockAPI Itembans = new ItemManager(DB); RememberedPos = new RemeberedPosManager(DB); RestApi = new SecureRest(IPAddress.Any, 8080); + RestApi.Verify += RestApi_Verify; RestManager = new RestManager(RestApi); RestManager.RegisterRestfulCommands(); if (Config.EnableGeoIP) @@ -216,6 +217,27 @@ namespace TShockAPI } } + RestObject RestApi_Verify(string username, string password) + { + var userAccount = TShock.Users.GetUserByName(username); + if (userAccount == null) + { + return new RestObject("401", "Invalid username/password combination provided. Please re-submit your query with a correct pair."); + } + + if (Tools.HashPassword(password).ToUpper() != userAccount.Password.ToUpper()) + { + return new RestObject("401", "Invalid username/password combination provided. Please re-submit your query with a correct pair."); + } + + if (!Tools.GetGroup(userAccount.Group).HasPermission("api") && userAccount.Group != "superadmin") + { + return new RestObject("403", "Although your account was successfully found and identified, your account lacks the permission required to use the API. (api)"); + } + + return new RestObject("200"); //Maybe return some user info too? + } + public override void DeInitialize() { GameHooks.PostInitialize -= OnPostInit;