source: binary-improvements2/WebServer/src/Permissions/AdminWebModules.cs@ 430

Last change on this file since 430 was 427, checked in by alloc, 19 months ago

*Save inherited per-method permission as "inherit" instead of the actual int.minValue string

File size: 8.5 KB
Line 
1using System.Collections.Generic;
2using System.Xml;
3using UnityEngine;
4
5namespace Webserver.Permissions {
6 public class AdminWebModules : AdminSectionAbs {
7 public static AdminWebModules Instance { get; private set; }
8
9 public AdminWebModules (AdminTools _parent) : base (_parent, "webmodules") {
10 Instance = this;
11 }
12
13 private readonly Dictionary<string, WebModule> modules = new CaseInsensitiveStringDictionary<WebModule> ();
14
15
16#region IO
17
18 public override void Clear () {
19 modules.Clear ();
20 }
21
22 protected override void ParseElement (XmlElement _childElement) {
23 if (WebModule.TryParse (_childElement, out WebModule webModule)) {
24 modules [webModule.Name] = webModule;
25 }
26 }
27
28 public override void Save (XmlElement _root) {
29 XmlElement modulesElement = _root.AddXmlElement (SectionTypeName);
30 // modulesElement.AddXmlComment (" <module name=\"adminuser1\" secret=\"supersecrettoken\" permission_level=\"0\" /> ");
31
32 foreach ((string _, WebModule module) in modules) {
33 module.ToXml (modulesElement);
34 }
35 }
36
37#endregion
38
39
40#region Runtime interaction
41
42
43 public void AddModule (WebModule _module) {
44 lock (this) {
45 allModulesList.Clear ();
46
47 modules [_module.Name] = _module;
48 Parent.Save ();
49 }
50 }
51
52 public bool RemoveModule (string _module) {
53 lock (this) {
54 allModulesList.Clear ();
55
56 bool removed = modules.Remove (_module);
57 if (removed) {
58 Parent.Save ();
59 }
60
61 return removed;
62 }
63 }
64
65 public List<WebModule> GetModules () {
66 lock (this) {
67 if (allModulesList.Count != 0) {
68 return allModulesList;
69 }
70
71 foreach ((string moduleName, WebModule moduleDefaultPerm) in knownModules) {
72 allModulesList.Add (modules.TryGetValue (moduleName, out WebModule modulePermission)
73 ? modulePermission
74 : moduleDefaultPerm);
75 }
76
77 return allModulesList;
78 }
79 }
80
81#endregion
82
83 public struct WebModule {
84 private const string methodLevelInheritKeyword = "inherit";
85
86 public string Name;
87 public int LevelGlobal;
88 public int[] LevelPerMethod;
89 public bool IsDefault;
90
91 public WebModule (string _name, int _level, bool _isDefault = false) {
92 LevelPerMethod = null;
93
94 Name = _name;
95 LevelGlobal = _level;
96 IsDefault = _isDefault;
97 }
98
99 public WebModule (string _name, int _levelGlobal, int[] _levelPerMethod, bool _isDefault = false) {
100 if (_levelPerMethod == null || _levelPerMethod.Length != (int)ERequestMethod.Count) {
101 LevelPerMethod = createDefaultPerMethodArray ();
102
103 for (int i = 0; i < (int)ERequestMethod.Count; i++) {
104 if (_levelPerMethod != null && i < _levelPerMethod.Length) {
105 LevelPerMethod [i] = _levelPerMethod [i];
106 }
107 }
108 } else {
109 LevelPerMethod = _levelPerMethod;
110 }
111
112 Name = _name;
113 LevelGlobal = _levelGlobal;
114 IsDefault = _isDefault;
115 }
116
117 public void ToXml (XmlElement _parent) {
118 bool hasPerMethodLevels = LevelPerMethod != null;
119
120 XmlElement permissionElement = _parent.AddXmlElement ("module")
121 .SetAttrib ("name", Name)
122 .SetAttrib ("permission_level", LevelGlobal.ToString ());
123
124 if (!hasPerMethodLevels) {
125 return;
126 }
127
128 for (int i = 0; i < LevelPerMethod.Length; i++) {
129 ERequestMethod method = (ERequestMethod)i;
130 int level = LevelPerMethod [i];
131
132 if (level == MethodLevelNotSupported) {
133 continue;
134 }
135
136 permissionElement.AddXmlElement ("method")
137 .SetAttrib ("name", method.ToStringCached ())
138 .SetAttrib ("permission_level", level == MethodLevelInheritGlobal ? methodLevelInheritKeyword : level.ToString ());
139 }
140 }
141
142 public static bool TryParse (XmlElement _element, out WebModule _result) {
143 _result = default;
144
145
146 if (!_element.TryGetAttribute ("name", out string name)) {
147 Log.Warning ($"[Web] [Perms] Ignoring module-entry because of missing 'name' attribute: {_element.OuterXml}");
148 return false;
149 }
150
151 if (!_element.TryGetAttribute ("permission_level", out string permissionLevelString)) {
152 Log.Warning ($"[Web] [Perms] Ignoring module-entry because of missing 'permission_level' attribute: {_element.OuterXml}");
153 return false;
154 }
155
156 if (!int.TryParse (permissionLevelString, out int permissionLevel)) {
157 Log.Warning (
158 $"[Web] [Perms] Ignoring module-entry because of invalid (non-numeric) value for 'permission_level' attribute: {_element.OuterXml}");
159 return false;
160 }
161
162 int[] perMethodLevels = null;
163
164 foreach (XmlNode child in _element.ChildNodes) {
165 if (child.NodeType != XmlNodeType.Element) {
166 continue;
167 }
168
169 XmlElement childElem = (XmlElement)child;
170 if (childElem.Name != "method") {
171 Log.Warning ($"[Web] [Perms] Ignoring module child element, invalid element name: {childElem.OuterXml}");
172 continue;
173 }
174
175 if (!childElem.TryGetAttribute ("name", out string methodName)) {
176 Log.Warning ($"[Web] [Perms] Ignoring module child element, missing 'name' attribute: {childElem.OuterXml}");
177 continue;
178 }
179
180 if (!EnumUtils.TryParse (methodName, out ERequestMethod method, true)) {
181 Log.Warning (
182 $"[Web] [Perms] Ignoring module child element, unknown method name in 'name' attribute: {childElem.OuterXml}");
183 continue;
184 }
185
186 if (method >= ERequestMethod.Count) {
187 Log.Warning (
188 $"[Web] [Perms] Ignoring module child element, invalid method name in 'name' attribute: {childElem.OuterXml}");
189 continue;
190 }
191
192 if (!childElem.TryGetAttribute ("permission_level", out permissionLevelString)) {
193 Log.Warning ($"[Web] [Perms] Ignoring module child element, missing 'permission_level' attribute: {childElem.OuterXml}");
194 continue;
195 }
196
197 int methodPermissionLevel;
198 if (permissionLevelString.EqualsCaseInsensitive (methodLevelInheritKeyword)) {
199 methodPermissionLevel = MethodLevelInheritGlobal;
200 } else if (!int.TryParse (permissionLevelString, out methodPermissionLevel)) {
201 Log.Warning (
202 $"[Web] [Perms] Ignoring module child element, invalid (non-numeric) value for 'permission_level' attribute: {childElem.OuterXml}");
203 continue;
204 }
205
206 perMethodLevels ??= createDefaultPerMethodArray ();
207 perMethodLevels [(int)method] = methodPermissionLevel;
208 }
209
210 _result = perMethodLevels != null ? new WebModule (name, permissionLevel, perMethodLevels) : new WebModule (name, permissionLevel);
211
212 return true;
213 }
214
215 private static int[] createDefaultPerMethodArray () {
216 int[] result = new int[(int)ERequestMethod.Count];
217
218 for (int i = 0; i < (int)ERequestMethod.Count; i++) {
219 result [i] = MethodLevelNotSupported;
220 }
221
222 return result;
223 }
224 }
225
226
227#region Specials
228
229 /// <summary>
230 /// Use global (API based) permission level for the method
231 /// </summary>
232 public const int MethodLevelInheritGlobal = int.MinValue;
233
234 /// <summary>
235 /// Method not supported
236 /// </summary>
237 public const int MethodLevelNotSupported = int.MinValue + 1;
238
239 public const int PermissionLevelUser = 1000;
240 public const int PermissionLevelGuest = 2000;
241
242 /// <summary>
243 /// Contains all registered modules and their default permission
244 /// </summary>
245 private readonly Dictionary<string, WebModule> knownModules = new CaseInsensitiveStringDictionary<WebModule> ();
246
247 /// <summary>
248 /// Public list of all modules, both those with custom permissions as well as those that do not with their default permission
249 /// </summary>
250 private readonly List<WebModule> allModulesList = new List<WebModule> ();
251
252 public void AddKnownModule (WebModule _module) {
253 if (string.IsNullOrEmpty (_module.Name)) {
254 return;
255 }
256
257 _module.IsDefault = true;
258
259 lock (this) {
260 allModulesList.Clear ();
261 knownModules [_module.Name] = _module;
262 }
263 }
264
265 public bool IsKnownModule (string _module) {
266 if (string.IsNullOrEmpty (_module)) {
267 return false;
268 }
269
270 lock (this) {
271 return knownModules.ContainsKey (_module);
272 }
273 }
274
275 public bool ModuleAllowedWithLevel (string _module, int _level) {
276 return GetModule (_module).LevelGlobal >= _level;
277 }
278
279 public WebModule GetModule (string _module) {
280 if (modules.TryGetValue (_module, out WebModule result)) {
281 return result;
282 }
283
284 return knownModules.TryGetValue (_module, out result) ? result : defaultModulePermission;
285 }
286
287 private readonly WebModule defaultModulePermission = new WebModule ("", 0, true);
288
289#endregion
290 }
291}
Note: See TracBrowser for help on using the repository browser.