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

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

*Updated web permissions system
*Fixed webpermissions command
*Moved API "webmods" to "mods", also lists non-webmod mods

File size: 8.2 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 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
92 Name = _name;
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;
112 IsDefault = _isDefault;
113 }
114
115 public void ToXml (XmlElement _parent) {
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 }
138 }
139
140 public static bool TryParse (XmlElement _element, out WebModule _result) {
141 _result = default;
142
143
144 if (!_element.TryGetAttribute ("name", out string name)) {
145 Log.Warning ($"[Web] [Perms] Ignoring module-entry because of missing 'name' attribute: {_element.OuterXml}");
146 return false;
147 }
148
149 if (!_element.TryGetAttribute ("permission_level", out string permissionLevelString)) {
150 Log.Warning ($"[Web] [Perms] Ignoring module-entry because of missing 'permission_level' attribute: {_element.OuterXml}");
151 return false;
152 }
153
154 if (!int.TryParse (permissionLevelString, out int permissionLevel)) {
155 Log.Warning (
156 $"[Web] [Perms] Ignoring module-entry because of invalid (non-numeric) value for 'permission_level' attribute: {_element.OuterXml}");
157 return false;
158 }
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
207 return true;
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 }
219 }
220
221
222#region Specials
223
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>
238 /// Contains all registered modules and their default permission
239 /// </summary>
240 private readonly Dictionary<string, WebModule> knownModules = new CaseInsensitiveStringDictionary<WebModule> ();
241
242 /// <summary>
243 /// Public list of all modules, both those with custom permissions as well as those that do not with their default permission
244 /// </summary>
245 private readonly List<WebModule> allModulesList = new List<WebModule> ();
246
247 public void AddKnownModule (WebModule _module) {
248 if (string.IsNullOrEmpty (_module.Name)) {
249 return;
250 }
251
252 _module.IsDefault = true;
253
254 lock (this) {
255 allModulesList.Clear ();
256 knownModules [_module.Name] = _module;
257 }
258 }
259
260 public bool IsKnownModule (string _module) {
261 if (string.IsNullOrEmpty (_module)) {
262 return false;
263 }
264
265 lock (this) {
266 return knownModules.ContainsKey (_module);
267 }
268 }
269
270 public bool ModuleAllowedWithLevel (string _module, int _level) {
271 return GetModule (_module).LevelGlobal >= _level;
272 }
273
274 public WebModule GetModule (string _module) {
275 if (modules.TryGetValue (_module, out WebModule result)) {
276 return result;
277 }
278
279 return knownModules.TryGetValue (_module, out result) ? result : defaultModulePermission;
280 }
281
282 private readonly WebModule defaultModulePermission = new WebModule ("", 0, true);
283
284#endregion
285 }
286}
Note: See TracBrowser for help on using the repository browser.