source: binary-improvements2/WebServer/src/WebPermissions.cs@ 399

Last change on this file since 399 was 399, checked in by alloc, 2 years ago

Updated logging strings

File size: 10.4 KB
RevLine 
[391]1using System.Collections.Generic;
2using System.Collections.ObjectModel;
3using System.IO;
4using System.Xml;
5
6namespace Webserver {
7 public class WebPermissions {
[395]8 private const string permissionsFileName = "webpermissions.xml";
[391]9 private static WebPermissions instance;
[395]10
11 private readonly FileSystemWatcher fileWatcher;
12
[391]13 private readonly WebModulePermission defaultModulePermission = new WebModulePermission ("", 0);
14
[395]15 /// <summary>
16 /// Registered user/pass admin tokens
17 /// </summary>
18 private readonly Dictionary<string, AdminToken> adminTokens = new CaseInsensitiveStringDictionary<AdminToken> ();
19
20 /// <summary>
21 /// Contains all registered modules and their default permission
22 /// </summary>
23 private readonly Dictionary<string, WebModulePermission> knownModules = new CaseInsensitiveStringDictionary<WebModulePermission> ();
24
25 /// <summary>
26 /// Manually defined module permissions
27 /// </summary>
28 private readonly Dictionary<string, WebModulePermission> modulePermissions =
[391]29 new CaseInsensitiveStringDictionary<WebModulePermission> ();
30
[395]31 /// <summary>
32 /// Public list of all modules, both those with custom permissions as well as those that do not with their default permission
33 /// </summary>
34 private readonly List<WebModulePermission> allModulesList = new List<WebModulePermission> ();
[391]35
[395]36 private readonly ReadOnlyCollection<WebModulePermission> allModulesListRo;
[391]37
[395]38 private static string SettingsFilePath => GamePrefs.GetString (EnumUtils.Parse<EnumGamePrefs> ("SaveGameFolder"));
39 private static string SettingsFileName => permissionsFileName;
40 private static string SettingsFullPath => SettingsFilePath + "/" + SettingsFileName;
41
[391]42 private WebPermissions () {
43 allModulesListRo = new ReadOnlyCollection<WebModulePermission> (allModulesList);
[395]44
45 Directory.CreateDirectory (SettingsFilePath);
46
[391]47 Load ();
[395]48
49 fileWatcher = new FileSystemWatcher (SettingsFilePath, SettingsFileName);
50 fileWatcher.Changed += OnFileChanged;
51 fileWatcher.Created += OnFileChanged;
52 fileWatcher.Deleted += OnFileChanged;
53 fileWatcher.EnableRaisingEvents = true;
[391]54 }
55
56 public static WebPermissions Instance {
57 get {
58 lock (typeof (WebPermissions)) {
59 return instance ??= new WebPermissions ();
60 }
61 }
62 }
63
64
[395]65#region Admin Tokens
[391]66
67 public void AddAdmin (string _name, string _token, int _permissionLevel, bool _save = true) {
68 AdminToken c = new AdminToken (_name, _token, _permissionLevel);
69 lock (this) {
[395]70 adminTokens [_name] = c;
[391]71 if (_save) {
72 Save ();
73 }
74 }
75 }
76
77 public void RemoveAdmin (string _name, bool _save = true) {
78 lock (this) {
[395]79 adminTokens.Remove (_name);
[391]80 if (_save) {
81 Save ();
82 }
83 }
84 }
85
86 public bool IsAdmin (string _name) {
[395]87 return adminTokens.ContainsKey (_name);
[391]88 }
89
90 public AdminToken[] GetAdmins () {
[395]91 AdminToken[] result = new AdminToken[adminTokens.Count];
92 adminTokens.CopyValuesTo (result);
[391]93 return result;
94 }
95
[395]96 public AdminToken GetWebAdmin (string _name, string _token) {
97 if (IsAdmin (_name) && adminTokens [_name].token == _token) {
98 return adminTokens [_name];
99 }
[391]100
[395]101 return null;
102 }
103
104#endregion
105
106
107#region Modules
108
[391]109 public void AddModulePermission (string _module, int _permissionLevel, bool _save = true) {
110 WebModulePermission p = new WebModulePermission (_module, _permissionLevel);
111 lock (this) {
112 allModulesList.Clear ();
[395]113 modulePermissions [_module] = p;
[391]114 if (_save) {
115 Save ();
116 }
117 }
118 }
119
120 public void AddKnownModule (string _module, int _defaultPermission) {
121 if (string.IsNullOrEmpty (_module)) {
122 return;
123 }
[395]124
[391]125 WebModulePermission p = new WebModulePermission (_module, _defaultPermission);
126
127 lock (this) {
128 allModulesList.Clear ();
129 knownModules [_module] = p;
130 }
131 }
132
133 public bool IsKnownModule (string _module) {
134 if (string.IsNullOrEmpty (_module)) {
135 return false;
136 }
137
138 lock (this) {
139 return knownModules.ContainsKey (_module);
140 }
141 }
142
143 public void RemoveModulePermission (string _module, bool _save = true) {
144 lock (this) {
145 allModulesList.Clear ();
[395]146 modulePermissions.Remove (_module);
[391]147 if (_save) {
148 Save ();
149 }
150 }
151 }
152
153 public IList<WebModulePermission> GetModules () {
154 if (allModulesList.Count != 0) {
155 return allModulesListRo;
156 }
157
158 foreach ((string moduleName, WebModulePermission moduleDefaultPerm) in knownModules) {
[395]159 allModulesList.Add (modulePermissions.TryGetValue (moduleName, out WebModulePermission modulePermission)
[391]160 ? modulePermission
161 : moduleDefaultPerm);
162 }
163
164 return allModulesListRo;
165 }
166
[395]167 public bool ModuleAllowedWithLevel (string _module, int _level) {
168 WebModulePermission permInfo = GetModulePermission (_module);
169 return permInfo.permissionLevel >= _level;
170 }
[391]171
[395]172 public WebModulePermission GetModulePermission (string _module) {
173 if (modulePermissions.TryGetValue (_module, out WebModulePermission result)) {
174 return result;
175 }
[391]176
[395]177 return knownModules.TryGetValue (_module, out result) ? result : defaultModulePermission;
[391]178 }
179
[395]180#endregion
[391]181
182
[395]183#region IO Tasks
[391]184
[395]185 private void OnFileChanged (object _source, FileSystemEventArgs _e) {
[399]186 Log.Out ("[Web] [Perms] Reloading " + SettingsFileName);
[395]187 Load ();
[391]188 }
189
190 public void Load () {
[395]191 adminTokens.Clear ();
192 modulePermissions.Clear ();
[391]193
[395]194 if (!File.Exists (SettingsFullPath)) {
[399]195 Log.Out ($"[Web] [Perms] Permissions file '{SettingsFileName}' not found, creating.");
[391]196 Save ();
197 return;
198 }
199
[399]200 Log.Out ($"[Web] [Perms] Loading permissions file at '{SettingsFullPath}'");
[391]201
202 XmlDocument xmlDoc = new XmlDocument ();
203
204 try {
[395]205 xmlDoc.Load (SettingsFullPath);
[391]206 } catch (XmlException e) {
[399]207 Log.Error ("[Web] [Perms] Failed loading permissions file: " + e.Message);
[391]208 return;
209 }
210
211 XmlNode adminToolsNode = xmlDoc.DocumentElement;
212
213 if (adminToolsNode == null) {
[399]214 Log.Error ("[Web] [Perms] Failed loading permissions file: No DocumentElement found");
[391]215 return;
216 }
[395]217
[391]218 foreach (XmlNode childNode in adminToolsNode.ChildNodes) {
[395]219 switch (childNode.Name) {
220 case "admintokens":
221 ParseAdminTokens (childNode);
222 break;
223 case "permissions":
224 ParseModulePermissions (childNode);
225 break;
226 }
227 }
[391]228
[399]229 Log.Out ("[Web] [Perms] Loading permissions file done.");
[395]230 }
[391]231
[395]232 private void ParseAdminTokens (XmlNode _baseNode) {
233 foreach (XmlNode subChild in _baseNode.ChildNodes) {
234 if (subChild.NodeType == XmlNodeType.Comment) {
235 continue;
236 }
[391]237
[395]238 if (subChild.NodeType != XmlNodeType.Element) {
[399]239 Log.Warning ($"[Web] [Perms] Unexpected XML node found in 'admintokens' section: {subChild.OuterXml}");
[395]240 continue;
241 }
[391]242
[395]243 XmlElement lineItem = (XmlElement)subChild;
[391]244
[395]245 if (!lineItem.HasAttribute ("name")) {
[399]246 Log.Warning ($"[Web] [Perms] Ignoring admintoken-entry because of missing 'name' attribute: {subChild.OuterXml}");
[395]247 continue;
248 }
[391]249
[395]250 if (!lineItem.HasAttribute ("token")) {
[399]251 Log.Warning ($"[Web] [Perms] Ignoring admintoken-entry because of missing 'token' attribute: {subChild.OuterXml}");
[395]252 continue;
253 }
[391]254
[395]255 if (!lineItem.HasAttribute ("permission_level")) {
[399]256 Log.Warning ($"[Web] [Perms] Ignoring admintoken-entry because of missing 'permission_level' attribute: {subChild.OuterXml}");
[395]257 continue;
[391]258 }
259
[395]260 string name = lineItem.GetAttribute ("name");
261 string token = lineItem.GetAttribute ("token");
262 if (!int.TryParse (lineItem.GetAttribute ("permission_level"), out int permissionLevel)) {
263 Log.Warning (
[399]264 $"[Web] [Perms] Ignoring admintoken-entry because of invalid (non-numeric) value for 'permission_level' attribute: {subChild.OuterXml}");
[395]265 continue;
266 }
[391]267
[395]268 AddAdmin (name, token, permissionLevel, false);
269 }
270 }
[391]271
[395]272 private void ParseModulePermissions (XmlNode _baseNode) {
273 foreach (XmlNode subChild in _baseNode.ChildNodes) {
274 if (subChild.NodeType == XmlNodeType.Comment) {
275 continue;
276 }
[391]277
[395]278 if (subChild.NodeType != XmlNodeType.Element) {
[399]279 Log.Warning ($"[Web] [Perms] Unexpected XML node found in 'permissions' section: {subChild.OuterXml}");
[395]280 continue;
281 }
[391]282
[395]283 XmlElement lineItem = (XmlElement)subChild;
[391]284
[395]285 if (!lineItem.HasAttribute ("module")) {
[399]286 Log.Warning ($"[Web] [Perms] Ignoring permission-entry because of missing 'module' attribute: {subChild.OuterXml}");
[395]287 continue;
288 }
[391]289
[395]290 if (!lineItem.HasAttribute ("permission_level")) {
[399]291 Log.Warning ($"[Web] [Perms] Ignoring permission-entry because of missing 'permission_level' attribute: {subChild.OuterXml}");
[395]292 continue;
[391]293 }
[395]294
295 if (!int.TryParse (lineItem.GetAttribute ("permission_level"), out int permissionLevel)) {
296 Log.Warning (
[399]297 $"[Web] [Perms] Ignoring permission-entry because of invalid (non-numeric) value for 'permission_level' attribute: {subChild.OuterXml}");
[395]298 continue;
299 }
300
301 AddModulePermission (lineItem.GetAttribute ("module"), permissionLevel, false);
[391]302 }
303 }
304
305 public void Save () {
[395]306 XmlDocument xml = new XmlDocument ();
[391]307
[395]308 xml.CreateXmlDeclaration ();
[391]309
[395]310 // xml.AddXmlComment (XmlHeader);
[391]311
[395]312 XmlElement root = xml.AddXmlElement ("webpermissions");
[391]313
[395]314 // AdminTokens
315 XmlElement adminTokensElem = root.AddXmlElement ("admintokens");
316 adminTokensElem.AddXmlComment (" <token name=\"adminuser1\" token=\"supersecrettoken\" permission_level=\"0\" /> ");
317 foreach ((string _, AdminToken adminToken) in adminTokens) {
318 adminTokensElem.AddXmlElement ("token")
319 .SetAttrib ("name", adminToken.name)
320 .SetAttrib ("token", adminToken.token)
321 .SetAttrib ("permission_level", adminToken.permissionLevel.ToString ());
[391]322 }
323
[395]324 XmlElement modulePermissionsElem = root.AddXmlElement ("permissions");
325 foreach ((string _, WebModulePermission webModulePermission) in modulePermissions) {
326 modulePermissionsElem.AddXmlElement ("permission")
327 .SetAttrib ("module", webModulePermission.module)
328 .SetAttrib ("permission_level", webModulePermission.permissionLevel.ToString ());
329 }
330
331
332 fileWatcher.EnableRaisingEvents = false;
333 xml.Save (SettingsFullPath);
[391]334 fileWatcher.EnableRaisingEvents = true;
335 }
336
[395]337#endregion
[391]338
[395]339
[391]340 public class AdminToken {
341 public readonly string name;
342 public readonly int permissionLevel;
343 public readonly string token;
344
345 public AdminToken (string _name, string _token, int _permissionLevel) {
346 name = _name;
347 token = _token;
348 permissionLevel = _permissionLevel;
349 }
350 }
351
352 public struct WebModulePermission {
353 public readonly string module;
354 public readonly int permissionLevel;
355
356 public WebModulePermission (string _module, int _permissionLevel) {
357 module = _module;
358 permissionLevel = _permissionLevel;
359 }
360 }
361 }
362}
Note: See TracBrowser for help on using the repository browser.