Changeset 426 for binary-improvements2/WebServer
- Timestamp:
- Apr 24, 2023, 2:40:34 PM (19 months ago)
- Location:
- binary-improvements2/WebServer
- Files:
-
- 1 added
- 18 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
binary-improvements2/WebServer/ModInfo.xml
r425 r426 5 5 <Description value="Integrated Webserver for the Web Dashboard and server APIs" /> 6 6 <Author value="The Fun Pimps LLC" /> 7 <Version value="21.0.2 58.0" />7 <Version value="21.0.270.0" /> 8 8 <Website value="" /> 9 9 </xml> -
binary-improvements2/WebServer/WebServer.csproj
r425 r426 101 101 </ItemGroup> 102 102 <ItemGroup> 103 <Compile Include="src\ERequestMethod.cs" /> 103 104 <Compile Include="src\FileCache\AbstractCache.cs" /> 104 105 <Compile Include="src\FileCache\DirectAccess.cs" /> … … 133 134 <Compile Include="src\WebAPI\APIs\ServerInfo.cs" /> 134 135 <Compile Include="src\WebAPI\APIs\ServerStats.cs" /> 135 <Compile Include="src\WebAPI\APIs\ WebMods.cs" />136 <Compile Include="src\WebAPI\APIs\Mods.cs" /> 136 137 <Compile Include="src\WebAPI\APIs\WebUiUpdates.cs" /> 137 138 <Compile Include="src\WebAPI\JsonCommons.cs" /> -
binary-improvements2/WebServer/src/Commands/WebPermissionsCmd.cs
r419 r426 15 15 16 16 protected override string getHelp () { 17 return "Set/get permission levels required to access a given web functionality. Default\n" + 18 "level required for functions that are not explicitly specified is 0.\n" + 19 "Usage:\n" + 20 " webpermission add <webfunction> <level>\n" + 21 " webpermission remove <webfunction>\n" + 22 " webpermission list [includedefaults]"; 17 return @" 18 |Set/get permission levels required to access a given web functionality. Default 19 |level required for functions that are not explicitly specified is 0. 20 |Usage: 21 | 1. webpermission add <webfunction> <method> <level> 22 | 2. webpermission remove <webfunction> 23 | 3. webpermission list [includedefaults] 24 |1. Add a new override (or replace the existing one) for the given function. Method must be a HTTP method (like 'GET', 'POST') 25 supported by the function or the keyword 'global' for a per-API permission level. Use the permission level keyword 26 'inherit' to use the per-API permission level for the specified method instead of a custom one for just the single method. 27 |2. Removes any custom overrides for the specified function. 28 |3. List all permissions. Pass in 'true' for the includedefaults argument to also show functions that do not have a custom override defined. 29 ".Unindent (); 23 30 } 24 31 … … 40 47 41 48 private void ExecuteAdd (List<string> _params) { 42 if (_params.Count != 3) {43 SdtdConsole.Instance.Output ($"Wrong number of arguments, expected 3, found {_params.Count}.");49 if (_params.Count != 4) { 50 SdtdConsole.Instance.Output ($"Wrong number of arguments, expected 4, found {_params.Count}."); 44 51 return; 45 52 } 46 53 47 if (!AdminWebModules.Instance.IsKnownModule (_params [1])) { 48 SdtdConsole.Instance.Output ($"\"{_params [1]}\" is not a valid web function."); 54 string moduleString = _params [1]; 55 string methodString = _params [2]; 56 string permissionLevelString = _params [3]; 57 58 ERequestMethod method = ERequestMethod.Count; 59 bool isGlobal = false; 60 bool isInherit = false; 61 int level; 62 63 if (!AdminWebModules.Instance.IsKnownModule (moduleString)) { 64 SdtdConsole.Instance.Output ($"\"{moduleString}\" is not a valid web function."); 49 65 return; 50 66 } 51 67 52 if (!int.TryParse (_params [2], out int level)) { 53 SdtdConsole.Instance.Output ($"\"{_params [2]}\" is not a valid integer."); 54 return; 68 AdminWebModules.WebModule module = AdminWebModules.Instance.GetModule (moduleString); 69 70 if (methodString.EqualsCaseInsensitive ("global")) { 71 isGlobal = true; 72 } else { 73 if (!EnumUtils.TryParse (methodString, out method, true)) { 74 SdtdConsole.Instance.Output ($"\"{methodString}\" is neither a valid HTTP method nor the 'global' keyword."); 75 return; 76 } 77 78 if (module.LevelPerMethod == null || module.LevelPerMethod [(int)method] == AdminWebModules.MethodLevelNotSupported) { 79 SdtdConsole.Instance.Output ($"\"{methodString}\" is not a method supported by the \"{moduleString}\" function."); 80 return; 81 } 55 82 } 56 83 57 AdminWebModules.Instance.AddModule (_params [1], level); 58 SdtdConsole.Instance.Output ($"{_params [1]} added with permission level of {level}."); 84 if (permissionLevelString.EqualsCaseInsensitive ("inherit")) { 85 if (isGlobal) { 86 SdtdConsole.Instance.Output ($"Permission level can not use the 'inherit' keyword with the 'global' method keyword."); 87 return; 88 } 89 90 isInherit = true; 91 level = AdminWebModules.MethodLevelInheritGlobal; 92 } else { 93 if (!int.TryParse (permissionLevelString, out level)) { 94 SdtdConsole.Instance.Output ($"\"{permissionLevelString}\" is neither a valid integer nor the 'inherit' keyword."); 95 return; 96 } 97 } 98 99 module.IsDefault = false; 100 if (isGlobal) { 101 module.LevelGlobal = level; 102 } else { 103 module.LevelPerMethod [(int)method] = level; 104 } 105 106 AdminWebModules.Instance.AddModule (module); 107 108 SdtdConsole.Instance.Output ( 109 $"{moduleString}, method {methodString} added {(isInherit ? ", inheriting the APIs global permission level" : "with permission level " + level)}."); 59 110 } 60 111 … … 78 129 79 130 SdtdConsole.Instance.Output ("Defined web function permissions:"); 80 SdtdConsole.Instance.Output (" Level: Web function");81 131 82 132 List<AdminWebModules.WebModule> wmps = AdminWebModules.Instance.GetModules (); 83 for (int i = 0; i < wmps.Count; i++) {84 AdminWebModules.WebModule wmp = wmps [i ];133 for (int iModule = 0; iModule < wmps.Count; iModule++) { 134 AdminWebModules.WebModule wmp = wmps [iModule]; 85 135 86 136 if (!includeDefaults && wmp.IsDefault) { … … 88 138 } 89 139 90 if (wmp.IsDefault) { 91 if (wmp.PermissionLevel == int.MinValue) { 92 SdtdConsole.Instance.Output ($" - : {wmp.Name} (default permission)"); 93 } else { 94 SdtdConsole.Instance.Output ($" {wmp.PermissionLevel,5}: {wmp.Name} (default permission)"); 140 SdtdConsole.Instance.Output ($" {wmp.Name,-25}: {wmp.LevelGlobal,4}{(wmp.IsDefault ? " (default permissions)" : "")}"); 141 if (wmp.LevelPerMethod != null) { 142 for (int iMethod = 0; iMethod < wmp.LevelPerMethod.Length; iMethod++) { 143 int methodLevel = wmp.LevelPerMethod [iMethod]; 144 ERequestMethod method = (ERequestMethod)iMethod; 145 146 if (methodLevel == AdminWebModules.MethodLevelNotSupported) { 147 continue; 148 } 149 150 if (methodLevel == AdminWebModules.MethodLevelInheritGlobal) { 151 SdtdConsole.Instance.Output ($" {method.ToStringCached (),25}: {wmp.LevelGlobal,4} (Using API level)"); 152 } else { 153 SdtdConsole.Instance.Output ($" {method.ToStringCached (),25}: {methodLevel,4}"); 154 } 95 155 } 96 } else {97 SdtdConsole.Instance.Output ($" {wmp.PermissionLevel,5}: {wmp.Name}");98 156 } 99 157 } -
binary-improvements2/WebServer/src/Permissions/AdminWebModules.cs
r418 r426 1 1 using System.Collections.Generic; 2 2 using System.Xml; 3 using UnityEngine; 3 4 4 5 namespace Webserver.Permissions { … … 40 41 41 42 42 public void AddModule (string _module, int _permissionLevel) { 43 WebModule p = new WebModule (_module, _permissionLevel, false); 43 public void AddModule (WebModule _module) { 44 44 lock (this) { 45 45 allModulesList.Clear (); 46 46 47 modules [_module ] = p;47 modules [_module.Name] = _module; 48 48 Parent.Save (); 49 49 } … … 80 80 81 81 #endregion 82 83 public readonly struct WebModule { 84 public readonly string Name; 85 public readonly int PermissionLevel; 86 public readonly bool IsDefault; 87 88 public WebModule (string _name, int _permissionLevel, bool _isDefault) { 82 83 public struct WebModule { 84 public string Name; 85 public int LevelGlobal; 86 public int[] LevelPerMethod; 87 public bool IsDefault; 88 89 public WebModule (string _name, int _level, bool _isDefault = false) { 90 LevelPerMethod = null; 91 89 92 Name = _name; 90 PermissionLevel = _permissionLevel; 93 LevelGlobal = _level; 94 IsDefault = _isDefault; 95 } 96 97 public WebModule (string _name, int _levelGlobal, int[] _levelPerMethod, bool _isDefault = false) { 98 if (_levelPerMethod == null || _levelPerMethod.Length != (int)ERequestMethod.Count) { 99 LevelPerMethod = createDefaultPerMethodArray (); 100 101 for (int i = 0; i < (int)ERequestMethod.Count; i++) { 102 if (_levelPerMethod != null && i < _levelPerMethod.Length) { 103 LevelPerMethod [i] = _levelPerMethod [i]; 104 } 105 } 106 } else { 107 LevelPerMethod = _levelPerMethod; 108 } 109 110 Name = _name; 111 LevelGlobal = _levelGlobal; 91 112 IsDefault = _isDefault; 92 113 } 93 114 94 115 public void ToXml (XmlElement _parent) { 95 _parent.AddXmlElement ("module") 96 .SetAttrib ("name", Name) 97 .SetAttrib ("permission_level", PermissionLevel.ToString ()); 116 bool hasPerMethodLevels = LevelPerMethod != null; 117 118 XmlElement permissionElement = _parent.AddXmlElement ("module") 119 .SetAttrib ("name", Name) 120 .SetAttrib ("permission_level", LevelGlobal.ToString ()); 121 122 if (!hasPerMethodLevels) { 123 return; 124 } 125 126 for (int i = 0; i < LevelPerMethod.Length; i++) { 127 ERequestMethod method = (ERequestMethod)i; 128 int level = LevelPerMethod [i]; 129 130 if (level == MethodLevelNotSupported) { 131 continue; 132 } 133 134 permissionElement.AddXmlElement ("method") 135 .SetAttrib ("name", method.ToStringCached ()) 136 .SetAttrib ("permission_level", level.ToString ()); 137 } 98 138 } 99 139 … … 117 157 return false; 118 158 } 119 120 _result = new WebModule (name, permissionLevel, false); 159 160 int[] perMethodLevels = null; 161 162 foreach (XmlNode child in _element.ChildNodes) { 163 if (child.NodeType != XmlNodeType.Element) { 164 continue; 165 } 166 167 XmlElement childElem = (XmlElement)child; 168 if (childElem.Name != "method") { 169 Log.Warning ($"[Web] [Perms] Ignoring module child element, invalid element name: {childElem.OuterXml}"); 170 continue; 171 } 172 173 if (!childElem.TryGetAttribute ("name", out string methodName)) { 174 Log.Warning ($"[Web] [Perms] Ignoring module child element, missing 'name' attribute: {childElem.OuterXml}"); 175 continue; 176 } 177 178 if (!EnumUtils.TryParse (methodName, out ERequestMethod method, true)) { 179 Log.Warning ( 180 $"[Web] [Perms] Ignoring module child element, unknown method name in 'name' attribute: {childElem.OuterXml}"); 181 continue; 182 } 183 184 if (method >= ERequestMethod.Count) { 185 Log.Warning ( 186 $"[Web] [Perms] Ignoring module child element, invalid method name in 'name' attribute: {childElem.OuterXml}"); 187 continue; 188 } 189 190 if (!childElem.TryGetAttribute ("permission_level", out permissionLevelString)) { 191 Log.Warning ($"[Web] [Perms] Ignoring module child element, missing 'permission_level' attribute: {childElem.OuterXml}"); 192 continue; 193 } 194 195 if (!int.TryParse (permissionLevelString, out int methodPermissionLevel)) { 196 Log.Warning ( 197 $"[Web] [Perms] Ignoring module child element, invalid (non-numeric) value for 'permission_level' attribute: {childElem.OuterXml}"); 198 continue; 199 } 200 201 perMethodLevels ??= createDefaultPerMethodArray (); 202 perMethodLevels [(int)method] = methodPermissionLevel; 203 } 204 205 _result = perMethodLevels != null ? new WebModule (name, permissionLevel, perMethodLevels) : new WebModule (name, permissionLevel); 206 121 207 return true; 122 208 } 209 210 private static int[] createDefaultPerMethodArray () { 211 int[] result = new int[(int)ERequestMethod.Count]; 212 213 for (int i = 0; i < (int)ERequestMethod.Count; i++) { 214 result [i] = MethodLevelNotSupported; 215 } 216 217 return result; 218 } 123 219 } 124 220 … … 127 223 128 224 /// <summary> 225 /// Use global (API based) permission level for the method 226 /// </summary> 227 public const int MethodLevelInheritGlobal = int.MinValue; 228 229 /// <summary> 230 /// Method not supported 231 /// </summary> 232 public const int MethodLevelNotSupported = int.MinValue + 1; 233 234 public const int PermissionLevelUser = 1000; 235 public const int PermissionLevelGuest = 2000; 236 237 /// <summary> 129 238 /// Contains all registered modules and their default permission 130 239 /// </summary> … … 136 245 private readonly List<WebModule> allModulesList = new List<WebModule> (); 137 246 138 public void AddKnownModule ( string _module, int _defaultPermission) {139 if (string.IsNullOrEmpty (_module )) {247 public void AddKnownModule (WebModule _module) { 248 if (string.IsNullOrEmpty (_module.Name)) { 140 249 return; 141 250 } 142 251 143 WebModule p = new WebModule (_module, _defaultPermission, true);144 252 _module.IsDefault = true; 253 145 254 lock (this) { 146 255 allModulesList.Clear (); 147 knownModules [_module ] = p;256 knownModules [_module.Name] = _module; 148 257 } 149 258 } … … 160 269 161 270 public bool ModuleAllowedWithLevel (string _module, int _level) { 162 WebModule permInfo = GetModule (_module)!.Value; 163 return permInfo.PermissionLevel >= _level; 164 } 165 166 public WebModule? GetModule (string _module, bool _returnDefaults = true) { 271 return GetModule (_module).LevelGlobal >= _level; 272 } 273 274 public WebModule GetModule (string _module) { 167 275 if (modules.TryGetValue (_module, out WebModule result)) { 168 276 return result; 169 }170 171 if (!_returnDefaults) {172 return null;173 277 } 174 278 -
binary-improvements2/WebServer/src/RequestContext.cs
r415 r426 2 2 3 3 namespace Webserver { 4 public enum ERequestMethod {5 Other,6 // ReSharper disable InconsistentNaming7 GET,8 PUT,9 POST,10 DELETE,11 HEAD,12 OPTIONS,13 // ReSharper restore InconsistentNaming14 Count15 }16 17 4 public class RequestContext { 18 5 public string RequestPath; -
binary-improvements2/WebServer/src/UrlHandlers/AbsHandler.cs
r404 r426 12 12 protected AbsHandler (string _moduleName, int _defaultPermissionLevel = 0) { 13 13 moduleName = _moduleName; 14 AdminWebModules.Instance.AddKnownModule ( _moduleName, _defaultPermissionLevel);14 AdminWebModules.Instance.AddKnownModule (new AdminWebModules.WebModule(_moduleName, _defaultPermissionLevel, true)); 15 15 } 16 16 -
binary-improvements2/WebServer/src/UrlHandlers/SseHandler.cs
r404 r426 53 53 public void AddEvent (string _eventName, AbsEvent _eventInstance) { 54 54 events.Add (_eventName, _eventInstance); 55 AdminWebModules.Instance.AddKnownModule ( $"webevent.{_eventName}", _eventInstance.DefaultPermissionLevel ());55 AdminWebModules.Instance.AddKnownModule (new AdminWebModules.WebModule($"webevent.{_eventName}", _eventInstance.DefaultPermissionLevel (), true)); 56 56 } 57 57 -
binary-improvements2/WebServer/src/UrlHandlers/UserStatusHandler.cs
r404 r426 16 16 private static readonly byte[] jsonAllowedKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("allowed"); 17 17 18 private static readonly byte[][] jsonMethodNameKeys; 19 20 static UserStatusHandler () { 21 jsonMethodNameKeys = new byte[(int)ERequestMethod.Count][]; 22 for (int i = 0; i < jsonMethodNameKeys.Length; i++) { 23 ERequestMethod method = (ERequestMethod)i; 24 jsonMethodNameKeys [i] = JsonWriter.GetEncodedPropertyName (method.ToStringCached ()); 25 } 26 } 27 18 28 public override void HandleRequest (RequestContext _context) { 19 29 WebUtils.PrepareEnvelopedResult (out JsonWriter writer); … … 32 42 33 43 List<AdminWebModules.WebModule> list = AdminWebModules.Instance.GetModules (); 34 for (int i = 0; i < list.Count; i++) {35 AdminWebModules.WebModule perm = list [i ];44 for (int iModule = 0; iModule < list.Count; iModule++) { 45 AdminWebModules.WebModule perm = list [iModule]; 36 46 37 if (i > 0) {47 if (iModule > 0) { 38 48 writer.WriteValueSeparator (); 39 49 } … … 43 53 44 54 writer.WriteRaw (jsonAllowedKey); 45 writer.WriteBoolean (perm.PermissionLevel >= _context.PermissionLevel); 55 56 writer.WriteBeginObject (); 57 58 if (perm.LevelPerMethod == null) { 59 writer.WriteRaw (jsonMethodNameKeys [(int)ERequestMethod.GET]); 60 writer.WriteBoolean (perm.LevelGlobal >= _context.PermissionLevel); 61 } else { 62 bool first = true; 63 for (int iMethod = 0; iMethod < perm.LevelPerMethod.Length; iMethod++) { 64 int methodLevel = perm.LevelPerMethod [iMethod]; 65 66 if (methodLevel == AdminWebModules.MethodLevelNotSupported) { 67 continue; 68 } 69 70 if (methodLevel == AdminWebModules.MethodLevelInheritGlobal) { 71 methodLevel = perm.LevelGlobal; 72 } 73 74 if (!first) { 75 writer.WriteValueSeparator (); 76 } 77 78 first = false; 79 80 writer.WriteRaw (jsonMethodNameKeys [iMethod]); 81 writer.WriteBoolean (methodLevel >= _context.PermissionLevel); 82 } 83 } 84 85 writer.WriteEndObject (); 86 46 87 47 88 writer.WriteEndObject (); -
binary-improvements2/WebServer/src/Web.cs
r415 r426 16 16 public static event Action<Web> ServerInitialized; 17 17 18 private const int guestPermissionLevel = 2000;19 18 private const string indexPageUrl = "/app"; 20 19 … … 51 50 } 52 51 53 // TODO: Read from config54 bool useCacheForStatic = StringParsers.ParseBool ("false");55 56 string webfilesFolder = DetectWebserverFolder (_modInstancePath);57 58 52 ConnectionHandler = new ConnectionHandler (); 59 53 60 RegisterPathHandler ("/", new RewriteHandler ("/files/")); 61 62 // React virtual routing 63 RegisterPathHandler ("/app", new RewriteHandler ("/files/index.html", true)); 64 65 // Do mods relatively early as they should not be requested a lot, unlike the later registrations, especially for API and map tiles 66 RegisterWebMods (useCacheForStatic); 67 68 RegisterPathHandler ("/session/", new SessionHandler (ConnectionHandler)); 69 RegisterPathHandler ("/userstatus", new UserStatusHandler ()); 70 RegisterPathHandler ("/sse/", new SseHandler ()); 71 RegisterPathHandler ("/files/", new StaticHandler ( 72 webfilesFolder, 73 useCacheForStatic ? new SimpleCache () : new DirectAccess (), 74 false) 75 ); 76 RegisterPathHandler ("/itemicons/", new ItemIconHandler (true)); 77 RegisterPathHandler ("/api/", new ApiHandler ()); 54 RegisterDefaultHandlers (_modInstancePath); 78 55 79 56 // Allow other code to add their stuff … … 94 71 } 95 72 73 private void RegisterDefaultHandlers (string _modInstancePath) { 74 // TODO: Read from config 75 bool useCacheForStatic = StringParsers.ParseBool ("false"); 76 77 string webfilesFolder = DetectWebserverFolder (_modInstancePath); 78 79 RegisterPathHandler ("/", new RewriteHandler ("/files/")); 80 81 // React virtual routing 82 RegisterPathHandler ("/app", new RewriteHandler ("/files/index.html", true)); 83 84 // Do mods relatively early as they should not be requested a lot, unlike the later registrations, especially for API and map tiles 85 RegisterWebMods (useCacheForStatic); 86 87 RegisterPathHandler ("/session/", new SessionHandler (ConnectionHandler)); 88 RegisterPathHandler ("/userstatus", new UserStatusHandler ()); 89 RegisterPathHandler ("/sse/", new SseHandler ()); 90 RegisterPathHandler ("/files/", new StaticHandler ( 91 webfilesFolder, 92 useCacheForStatic ? new SimpleCache () : new DirectAccess (), 93 false) 94 ); 95 RegisterPathHandler ("/itemicons/", new ItemIconHandler (true)); 96 RegisterPathHandler ("/api/", new ApiHandler ()); 97 } 98 96 99 private static string DetectWebserverFolder (string _modInstancePath) { 97 100 string webserverFolder = $"{_modInstancePath}/webserver"; … … 127 130 foreach (Mod mod in ModManager.GetLoadedMods ()) { 128 131 try { 129 string webModPath = $"{mod.Path}/WebMod";130 if (!Directory.Exists (webModPath)) {131 continue;132 }133 134 132 try { 135 133 WebMod webMod = new WebMod (this, mod, _useStaticCache); … … 298 296 if (reqRemoteEndPoint == null) { 299 297 Log.Warning ("[Web] No RemoteEndPoint on web request"); 300 return guestPermissionLevel;298 return AdminWebModules.PermissionLevelGuest; 301 299 } 302 300 … … 316 314 if (!_req.Headers.TryGetValue ("X-SDTD-API-TOKENNAME", out string apiTokenName) || 317 315 !_req.Headers.TryGetValue ("X-SDTD-API-SECRET", out string apiTokenSecret)) { 318 return guestPermissionLevel;316 return AdminWebModules.PermissionLevelGuest; 319 317 } 320 318 … … 326 324 Log.Warning ($"[Web] Invalid Admintoken used from {reqRemoteEndPoint}"); 327 325 328 return guestPermissionLevel;326 return AdminWebModules.PermissionLevelGuest; 329 327 } 330 328 } -
binary-improvements2/WebServer/src/WebAPI/APIs/Command.cs
r408 r426 3 3 using JetBrains.Annotations; 4 4 using Utf8Json; 5 using Webserver.Permissions; 5 6 6 7 namespace Webserver.WebAPI.APIs { … … 130 131 } 131 132 132 public override int DefaultPermissionLevel () => 2000;133 public override int DefaultPermissionLevel () => AdminWebModules.PermissionLevelGuest; 133 134 } 134 135 } -
binary-improvements2/WebServer/src/WebAPI/APIs/Mods.cs
r425 r426 1 1 using JetBrains.Annotations; 2 2 using Utf8Json; 3 using Webserver.Permissions; 3 4 4 5 namespace Webserver.WebAPI.APIs { 5 6 [UsedImplicitly] 6 public class WebMods : AbsRestApi {7 public class Mods : AbsRestApi { 7 8 private readonly byte[] loadedWebMods; 8 9 9 public WebMods (Web _parent) {10 public Mods (Web _parent) { 10 11 JsonWriter writer = new JsonWriter (); 11 12 writer.WriteBeginArray (); … … 13 14 for (int i = 0; i < _parent.webMods.Count; i++) { 14 15 WebMod webMod = _parent.webMods [i]; 15 16 16 17 if (i > 0) { 17 18 writer.WriteValueSeparator (); 18 19 } 19 20 20 21 writer.WriteBeginObject (); 21 22 22 writer.WriteString ("name"); 23 writer.WriteNameSeparator (); 24 writer.WriteString (webMod.ParentMod.Name); 23 writeModJson (ref writer, webMod); 25 24 26 string webModReactBundle = webMod.ReactBundle; 27 if (webModReactBundle != null) { 25 if (webMod.ReactBundle != null || webMod.CssPath != null) { 28 26 writer.WriteValueSeparator (); 29 writer.WriteString ("bundle");30 writer.WriteNameSeparator ();31 writer.WriteString (webModReactBundle);32 }33 27 34 string webModCssFile = webMod.CssPath; 35 if (webModCssFile != null) { 36 writer.WriteValueSeparator (); 37 writer.WriteString ("css"); 38 writer.WriteNameSeparator (); 39 writer.WriteString (webModCssFile); 28 writer.WritePropertyName ("web"); 29 writer.WriteBeginObject (); 30 31 string webModReactBundle = webMod.ReactBundle; 32 if (webModReactBundle != null) { 33 writer.WritePropertyName ("bundle"); 34 writer.WriteString (webModReactBundle); 35 } 36 37 string webModCssFile = webMod.CssPath; 38 if (webModCssFile != null) { 39 if (webModReactBundle != null) { 40 writer.WriteValueSeparator (); 41 } 42 43 writer.WritePropertyName ("css"); 44 writer.WriteString (webModCssFile); 45 } 46 47 writer.WriteEndObject (); 40 48 } 41 49 … … 54 62 } 55 63 56 public override int DefaultPermissionLevel () => 2000; 64 public override int DefaultPermissionLevel () => AdminWebModules.PermissionLevelGuest; 65 66 private void writeModJson (ref JsonWriter _writer, WebMod _webMod) { 67 _writer.WritePropertyName ("name"); 68 _writer.WriteString (_webMod.ParentMod.Name); 69 70 _writer.WriteValueSeparator (); 71 _writer.WritePropertyName ("displayName"); 72 JsonCommons.WriteStringOrNull (ref _writer, _webMod.ParentMod.DisplayName); 73 74 _writer.WriteValueSeparator (); 75 _writer.WritePropertyName ("description"); 76 JsonCommons.WriteStringOrNull (ref _writer, _webMod.ParentMod.Description); 77 78 _writer.WriteValueSeparator (); 79 _writer.WritePropertyName ("author"); 80 JsonCommons.WriteStringOrNull (ref _writer, _webMod.ParentMod.Author); 81 82 _writer.WriteValueSeparator (); 83 _writer.WritePropertyName ("version"); 84 JsonCommons.WriteStringOrNull (ref _writer, _webMod.ParentMod.VersionString); 85 86 _writer.WriteValueSeparator (); 87 _writer.WritePropertyName ("website"); 88 JsonCommons.WriteStringOrNull (ref _writer, _webMod.ParentMod.Website); 89 } 57 90 } 58 91 } -
binary-improvements2/WebServer/src/WebAPI/APIs/Player.cs
r425 r426 256 256 } 257 257 258 public override int DefaultPermissionLevel () => 2000;258 public override int DefaultPermissionLevel () => AdminWebModules.PermissionLevelGuest; 259 259 } 260 260 } -
binary-improvements2/WebServer/src/WebAPI/APIs/RegisterUser.cs
r416 r426 80 80 } 81 81 82 // TODO: Check if username is already used! 82 // TODO: Check if username is already used by someone else! 83 // TODO: Remove existing username if player already had one! 83 84 84 85 AdminWebUsers.Instance.AddUser (username, password, regData.PlatformUserId, regData.CrossPlatformUserId); … … 95 96 } 96 97 97 public override int DefaultPermissionLevel () => 2000;98 public override int DefaultPermissionLevel () => AdminWebModules.PermissionLevelGuest; 98 99 } 99 100 } -
binary-improvements2/WebServer/src/WebAPI/APIs/ServerStats.cs
r408 r426 2 2 using Utf8Json; 3 3 using Webserver.LiveData; 4 using Webserver.Permissions; 4 5 5 6 namespace Webserver.WebAPI.APIs { … … 47 48 } 48 49 49 public override int DefaultPermissionLevel () => 2000;50 public override int DefaultPermissionLevel () => AdminWebModules.PermissionLevelGuest; 50 51 } 51 52 } -
binary-improvements2/WebServer/src/WebAPI/APIs/WebUiUpdates.cs
r408 r426 2 2 using Utf8Json; 3 3 using Webserver.LiveData; 4 using Webserver.Permissions; 4 5 5 6 namespace Webserver.WebAPI.APIs { … … 57 58 } 58 59 59 public override int DefaultPermissionLevel () => 2000;60 public override int DefaultPermissionLevel () => AdminWebModules.PermissionLevelGuest; 60 61 } 61 62 } -
binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs
r418 r426 10 10 private static readonly UnityEngine.Profiling.CustomSampler jsonDeserializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Deserialize"); 11 11 12 protected readonly string[] CachedPerMethodModuleNames = new string[(int)ERequestMethod.Count];13 14 12 protected AbsRestApi (string _name = null) : this(null, _name) { 15 13 } … … 19 17 20 18 protected override void RegisterPermissions () { 21 base.RegisterPermissions (); 22 23 for (int i = 0; i < (int)ERequestMethod.Count; i++) { 24 ERequestMethod method = (ERequestMethod)i; 25 26 if (method is not (ERequestMethod.GET or ERequestMethod.PUT or ERequestMethod.POST or ERequestMethod.DELETE)) { 27 continue; 28 } 29 30 CachedPerMethodModuleNames [i] = $"webapi.{Name}:{method.ToStringCached ()}"; 31 AdminWebModules.Instance.AddKnownModule (CachedPerMethodModuleNames [i], DefaultMethodPermissionLevel (method)); 32 } 19 AdminWebModules.Instance.AddKnownModule (new AdminWebModules.WebModule (CachedApiModuleName, DefaultPermissionLevel (), 20 DefaultMethodPermissionLevels (), true)); 33 21 } 34 22 … … 136 124 137 125 public override bool Authorized (RequestContext _context) { 138 return ActiveMethodPermissionLevel (_context.Method) >= _context.PermissionLevel; 126 AdminWebModules.WebModule module = AdminWebModules.Instance.GetModule (CachedApiModuleName); 127 128 if (module.LevelPerMethod != null) { 129 int perMethodLevel = module.LevelPerMethod [(int)_context.Method]; 130 if (perMethodLevel == AdminWebModules.MethodLevelNotSupported) { 131 return false; 132 } 133 134 if (perMethodLevel != AdminWebModules.MethodLevelInheritGlobal) { 135 return perMethodLevel >= _context.PermissionLevel; 136 } 137 } 138 139 return module.LevelGlobal >= _context.PermissionLevel; 139 140 } 140 141 141 142 /// <summary> 142 /// Define default permission levels per HTTP method 143 /// Define default permission levels per HTTP method as an array of levels. See <see cref="ERequestMethod"/> for the order of entries. 143 144 /// </summary> 144 /// <param name="_method">HTTP method to return the default value for</param> 145 /// <returns>Default permission level for the given HTTP method. A value of int.MinValue means no per-method default, use per-API default</returns> 146 public virtual int DefaultMethodPermissionLevel (ERequestMethod _method) => int.MinValue; 147 148 public virtual int ActiveMethodPermissionLevel (ERequestMethod _method) { 149 string methodApiModuleName = CachedPerMethodModuleNames [(int)_method]; 150 151 if (methodApiModuleName == null) { 152 return 0; 153 } 154 155 AdminWebModules.WebModule? overrideModule = AdminWebModules.Instance.GetModule (methodApiModuleName, false); 156 if (overrideModule.HasValue) { 157 return overrideModule.Value.PermissionLevel; 158 } 159 160 overrideModule = AdminWebModules.Instance.GetModule (CachedApiModuleName, false); 161 if (overrideModule.HasValue) { 162 return overrideModule.Value.PermissionLevel; 163 } 164 165 int defaultMethodPermissionLevel = DefaultMethodPermissionLevel (_method); 166 // ReSharper disable once ConvertIfStatementToReturnStatement 167 if (defaultMethodPermissionLevel != int.MinValue) { 168 return defaultMethodPermissionLevel; 169 } 170 171 return DefaultPermissionLevel (); 172 } 145 /// <returns>Default permission levels for supported methods. See <see cref="AdminWebModules.MethodLevelNotSupported"/> and <see cref="AdminWebModules.MethodLevelInheritGlobal"/>.</returns> 146 public virtual int[] DefaultMethodPermissionLevels () => new[] { 147 AdminWebModules.MethodLevelNotSupported, 148 AdminWebModules.MethodLevelInheritGlobal, 149 AdminWebModules.MethodLevelInheritGlobal, 150 AdminWebModules.MethodLevelInheritGlobal, 151 AdminWebModules.MethodLevelInheritGlobal 152 }; 173 153 174 154 #region Helpers -
binary-improvements2/WebServer/src/WebAPI/AbsWebAPI.cs
r418 r426 19 19 20 20 protected virtual void RegisterPermissions () { 21 AdminWebModules.Instance.AddKnownModule ( $"webapi.{Name}", DefaultPermissionLevel ());21 AdminWebModules.Instance.AddKnownModule (new AdminWebModules.WebModule(CachedApiModuleName, DefaultPermissionLevel (), true)); 22 22 } 23 23 … … 25 25 26 26 public virtual bool Authorized (RequestContext _context) { 27 return AdminWebModules.Instance. ModuleAllowedWithLevel (CachedApiModuleName, _context.PermissionLevel);27 return AdminWebModules.Instance.GetModule (CachedApiModuleName).LevelGlobal >= _context.PermissionLevel; 28 28 } 29 29 -
binary-improvements2/WebServer/src/WebAPI/JsonCommons.cs
r425 r426 60 60 _writer.WriteString (_dateTime.ToString ("o")); 61 61 } 62 63 public static void WriteStringOrNull (ref JsonWriter _writer, string _string) { 64 if (_string == null) { 65 _writer.WriteNull (); 66 } else { 67 _writer.WriteString (_string); 68 } 69 } 62 70 } 63 71 } -
binary-improvements2/WebServer/src/WebMod.cs
r402 r426 12 12 public readonly string ReactBundle; // Absolute web path to the React bundle if the mod has one, e.g. "/webmods/myMod/bundle.js" 13 13 public readonly string CssPath; // Absolute web path to a CSS if the mod has one, e.g. "/webmods/myMod/styling.css"; 14 public readonly bool IsWebMod; 14 15 15 16 public WebMod (Web _parentWeb, Mod _parentMod, bool _useStaticCache) { 16 string folder = $"{_parentMod.Path}/WebMod";17 if (!Directory.Exists (folder)) {18 throw new InvalidDataException("No WebMod folder in mod");19 }20 21 string urlWebModBase = $"{modsBaseUrl}{_parentMod.FolderName}/";22 23 ReactBundle = $"{folder}/{reactBundleName}";24 ReactBundle = File.Exists (ReactBundle) ? $"{urlWebModBase}{reactBundleName}" : null;25 26 CssPath = $"{folder}/{stylingFileName}";27 CssPath = File.Exists (CssPath) ? $"{urlWebModBase}{stylingFileName}" : null;28 29 if (ReactBundle == null && CssPath == null) {30 throw new InvalidDataException($"WebMod folder has neither a {reactBundleName} nor a {stylingFileName}");31 }32 33 17 ParentMod = _parentMod; 34 18 35 _parentWeb.RegisterPathHandler (urlWebModBase, new StaticHandler ( 36 folder, 37 _useStaticCache ? new SimpleCache () : new DirectAccess (), 38 false) 39 ); 19 string folder = $"{_parentMod.Path}/WebMod"; 20 IsWebMod = Directory.Exists (folder); 21 22 if (IsWebMod) { 23 string urlWebModBase = $"{modsBaseUrl}{_parentMod.FolderName}/"; 24 25 ReactBundle = $"{folder}/{reactBundleName}"; 26 ReactBundle = File.Exists (ReactBundle) ? $"{urlWebModBase}{reactBundleName}" : null; 27 28 CssPath = $"{folder}/{stylingFileName}"; 29 CssPath = File.Exists (CssPath) ? $"{urlWebModBase}{stylingFileName}" : null; 30 31 _parentWeb.RegisterPathHandler (urlWebModBase, new StaticHandler ( 32 folder, 33 _useStaticCache ? new SimpleCache () : new DirectAccess (), 34 false) 35 ); 36 } 40 37 } 41 38 }
Note:
See TracChangeset
for help on using the changeset viewer.