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

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

Major refactoring/cleanup

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