using System; using System.Collections.Generic; using System.Net; using System.Reflection; using Webserver.WebAPI; namespace Webserver.UrlHandlers { public class ApiHandler : AbsHandler { private readonly Dictionary apis = new CaseInsensitiveStringDictionary (); public ApiHandler () : base (null) { } public override void SetBasePathAndParent (Web _parent, string _relativePath) { base.SetBasePathAndParent (_parent, _relativePath); Type[] apiWithParentCtorTypes = { typeof (Web) }; object[] apiWithParentCtorArgs = { _parent }; Type[] apiEmptyCtorTypes = { }; object[] apiEmptyCtorArgs = { }; ReflectionHelpers.FindTypesImplementingBase (typeof (AbsWebAPI), _type => { ConstructorInfo ctor = _type.GetConstructor (apiWithParentCtorTypes); if (ctor != null) { AbsWebAPI apiInstance = (AbsWebAPI) ctor.Invoke (apiWithParentCtorArgs); addApi (apiInstance); return; } ctor = _type.GetConstructor (apiEmptyCtorTypes); if (ctor != null) { AbsWebAPI apiInstance = (AbsWebAPI) ctor.Invoke (apiEmptyCtorArgs); addApi (apiInstance); } }); // Permissions that don't map to a real API addApi (new Null ("viewallclaims")); addApi (new Null ("viewallplayers")); } private void addApi (AbsWebAPI _api) { apis.Add (_api.Name, _api); WebPermissions.Instance.AddKnownModule ($"webapi.{_api.Name}", _api.DefaultPermissionLevel ()); } private static readonly UnityEngine.Profiling.CustomSampler apiHandlerSampler = UnityEngine.Profiling.CustomSampler.Create ("API_Handler"); public override void HandleRequest (RequestContext _context) { string apiName; string subPath = null; int pathSeparatorIndex = _context.RequestPath.IndexOf ('/', urlBasePath.Length); if (pathSeparatorIndex >= 0) { apiName = _context.RequestPath.Substring (urlBasePath.Length, pathSeparatorIndex - urlBasePath.Length); subPath = _context.RequestPath.Substring (pathSeparatorIndex + 1); } else { apiName = _context.RequestPath.Substring (urlBasePath.Length); } if (!apis.TryGetValue (apiName, out AbsWebAPI api)) { Log.Warning ($"[Web] In {nameof(ApiHandler)}.HandleRequest(): No handler found for API \"{apiName}\""); _context.Response.StatusCode = (int) HttpStatusCode.NotFound; return; } if (!IsAuthorizedForApi (apiName, _context.PermissionLevel)) { _context.Response.StatusCode = (int) HttpStatusCode.Forbidden; if (_context.Connection != null) { //Log.Out ($"{nameof(ApiHandler)}: user '{user.SteamID}' not allowed to execute '{apiName}'"); } return; } _context.RequestPath = subPath; try { apiHandlerSampler.Begin (); api.HandleRequest (_context); apiHandlerSampler.End (); } catch (Exception e) { Log.Error ($"[Web] In {nameof(ApiHandler)}.HandleRequest(): Handler {api.Name} threw an exception:"); Log.Exception (e); _context.Response.StatusCode = (int) HttpStatusCode.InternalServerError; } } private bool IsAuthorizedForApi (string _apiName, int _permissionLevel) { return WebPermissions.Instance.ModuleAllowedWithLevel ($"webapi.{_apiName}", _permissionLevel); } } }