source: TFP-WebServer/WebServer/src/Permissions/AdminWebModules.cs@ 457

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

Added WebModules API POST support

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