Changeset 395


Ignore:
Timestamp:
Aug 8, 2022, 8:09:28 PM (2 years ago)
Author:
alloc
Message:

WebPermissions cleanup, also now makes sure to write proper XML

File:
1 edited

Legend:

Unmodified
Added
Removed
  • binary-improvements2/WebServer/src/WebPermissions.cs

    r391 r395  
    66namespace Webserver {
    77        public class WebPermissions {
    8                 private const string permissionsFile = "webpermissions.xml";
     8                private const string permissionsFileName = "webpermissions.xml";
    99                private static WebPermissions instance;
     10
     11                private readonly FileSystemWatcher fileWatcher;
     12
    1013                private readonly WebModulePermission defaultModulePermission = new WebModulePermission ("", 0);
    1114
    12                 private readonly Dictionary<string, WebModulePermission> knownModules =
     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 =
    1329                        new CaseInsensitiveStringDictionary<WebModulePermission> ();
    1430
    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> ();
     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> ();
     35
     36                private readonly ReadOnlyCollection<WebModulePermission> allModulesListRo;
     37
     38                private static string SettingsFilePath => GamePrefs.GetString (EnumUtils.Parse<EnumGamePrefs> ("SaveGameFolder"));
     39                private static string SettingsFileName => permissionsFileName;
     40                private static string SettingsFullPath => SettingsFilePath + "/" + SettingsFileName;
    1941
    2042                private WebPermissions () {
    21                         allModulesList = new List<WebModulePermission> ();
    2243                        allModulesListRo = new ReadOnlyCollection<WebModulePermission> (allModulesList);
    23                         Directory.CreateDirectory (GetFilePath ());
    24                         InitFileWatcher ();
     44
     45                        Directory.CreateDirectory (SettingsFilePath);
     46
    2547                        Load ();
     48
     49                        fileWatcher = new FileSystemWatcher (SettingsFilePath, SettingsFileName);
     50                        fileWatcher.Changed += OnFileChanged;
     51                        fileWatcher.Created += OnFileChanged;
     52                        fileWatcher.Deleted += OnFileChanged;
     53                        fileWatcher.EnableRaisingEvents = true;
    2654                }
    2755
     
    3462                }
    3563
     64
     65#region Admin Tokens
     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) {
     70                                adminTokens [_name] = c;
     71                                if (_save) {
     72                                        Save ();
     73                                }
     74                        }
     75                }
     76
     77                public void RemoveAdmin (string _name, bool _save = true) {
     78                        lock (this) {
     79                                adminTokens.Remove (_name);
     80                                if (_save) {
     81                                        Save ();
     82                                }
     83                        }
     84                }
     85
     86                public bool IsAdmin (string _name) {
     87                        return adminTokens.ContainsKey (_name);
     88                }
     89
     90                public AdminToken[] GetAdmins () {
     91                        AdminToken[] result = new AdminToken[adminTokens.Count];
     92                        adminTokens.CopyValuesTo (result);
     93                        return result;
     94                }
     95
     96                public AdminToken GetWebAdmin (string _name, string _token) {
     97                        if (IsAdmin (_name) && adminTokens [_name].token == _token) {
     98                                return adminTokens [_name];
     99                        }
     100
     101                        return null;
     102                }
     103
     104#endregion
     105
     106
     107#region Modules
     108
     109                public void AddModulePermission (string _module, int _permissionLevel, bool _save = true) {
     110                        WebModulePermission p = new WebModulePermission (_module, _permissionLevel);
     111                        lock (this) {
     112                                allModulesList.Clear ();
     113                                modulePermissions [_module] = p;
     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                        }
     124
     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 ();
     146                                modulePermissions.Remove (_module);
     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) {
     159                                allModulesList.Add (modulePermissions.TryGetValue (moduleName, out WebModulePermission modulePermission)
     160                                        ? modulePermission
     161                                        : moduleDefaultPerm);
     162                        }
     163
     164                        return allModulesListRo;
     165                }
     166
    36167                public bool ModuleAllowedWithLevel (string _module, int _level) {
    37168                        WebModulePermission permInfo = GetModulePermission (_module);
     
    39170                }
    40171
    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 
    49172                public WebModulePermission GetModulePermission (string _module) {
    50                         if (modules.TryGetValue (_module, out WebModulePermission result)) {
     173                        if (modulePermissions.TryGetValue (_module, out WebModulePermission result)) {
    51174                                return result;
    52175                        }
     
    55178                }
    56179
    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                 }
     180#endregion
     181
     182
     183#region IO Tasks
    162184
    163185                private void OnFileChanged (object _source, FileSystemEventArgs _e) {
    164                         Log.Out ("Reloading " + permissionsFile);
     186                        Log.Out ("Reloading " + SettingsFileName);
    165187                        Load ();
    166188                }
    167189
    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 
    180190                public void Load () {
    181                         admintokens.Clear ();
    182                         modules.Clear ();
    183 
    184                         if (!File.Exists (GetFullPath ())) {
    185                                 Log.Out ($"Permissions file '{GetFileName ()}' not found, creating.");
     191                        adminTokens.Clear ();
     192                        modulePermissions.Clear ();
     193
     194                        if (!File.Exists (SettingsFullPath)) {
     195                                Log.Out ($"Permissions file '{SettingsFileName}' not found, creating.");
    186196                                Save ();
    187197                                return;
    188198                        }
    189199
    190                         Log.Out ($"Loading permissions file at '{GetFullPath ()}'");
     200                        Log.Out ($"Loading permissions file at '{SettingsFullPath}'");
    191201
    192202                        XmlDocument xmlDoc = new XmlDocument ();
    193203
    194204                        try {
    195                                 xmlDoc.Load (GetFullPath ());
     205                                xmlDoc.Load (SettingsFullPath);
    196206                        } catch (XmlException e) {
    197207                                Log.Error ("Failed loading permissions file: " + e.Message);
     
    205215                                return;
    206216                        }
     217
     218                        foreach (XmlNode childNode in adminToolsNode.ChildNodes) {
     219                                switch (childNode.Name) {
     220                                        case "admintokens":
     221                                                ParseAdminTokens (childNode);
     222                                                break;
     223                                        case "permissions":
     224                                                ParseModulePermissions (childNode);
     225                                                break;
     226                                }
     227                        }
     228
     229                        Log.Out ("Loading permissions file done.");
     230                }
     231
     232                private void ParseAdminTokens (XmlNode _baseNode) {
     233                        foreach (XmlNode subChild in _baseNode.ChildNodes) {
     234                                if (subChild.NodeType == XmlNodeType.Comment) {
     235                                        continue;
     236                                }
     237
     238                                if (subChild.NodeType != XmlNodeType.Element) {
     239                                        Log.Warning ($"Unexpected XML node found in 'admintokens' section: {subChild.OuterXml}");
     240                                        continue;
     241                                }
     242
     243                                XmlElement lineItem = (XmlElement)subChild;
     244
     245                                if (!lineItem.HasAttribute ("name")) {
     246                                        Log.Warning ($"Ignoring admintoken-entry because of missing 'name' attribute: {subChild.OuterXml}");
     247                                        continue;
     248                                }
     249
     250                                if (!lineItem.HasAttribute ("token")) {
     251                                        Log.Warning ($"Ignoring admintoken-entry because of missing 'token' attribute: {subChild.OuterXml}");
     252                                        continue;
     253                                }
     254
     255                                if (!lineItem.HasAttribute ("permission_level")) {
     256                                        Log.Warning ($"Ignoring admintoken-entry because of missing 'permission_level' attribute: {subChild.OuterXml}");
     257                                        continue;
     258                                }
     259
     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 (
     264                                                $"Ignoring admintoken-entry because of invalid (non-numeric) value for 'permission_level' attribute: {subChild.OuterXml}");
     265                                        continue;
     266                                }
     267
     268                                AddAdmin (name, token, permissionLevel, false);
     269                        }
     270                }
     271
     272                private void ParseModulePermissions (XmlNode _baseNode) {
     273                        foreach (XmlNode subChild in _baseNode.ChildNodes) {
     274                                if (subChild.NodeType == XmlNodeType.Comment) {
     275                                        continue;
     276                                }
     277
     278                                if (subChild.NodeType != XmlNodeType.Element) {
     279                                        Log.Warning ($"Unexpected XML node found in 'permissions' section: {subChild.OuterXml}");
     280                                        continue;
     281                                }
     282
     283                                XmlElement lineItem = (XmlElement)subChild;
     284
     285                                if (!lineItem.HasAttribute ("module")) {
     286                                        Log.Warning ($"Ignoring permission-entry because of missing 'module' attribute: {subChild.OuterXml}");
     287                                        continue;
     288                                }
     289
     290                                if (!lineItem.HasAttribute ("permission_level")) {
     291                                        Log.Warning ($"Ignoring permission-entry because of missing 'permission_level' attribute: {subChild.OuterXml}");
     292                                        continue;
     293                                }
     294
     295                                if (!int.TryParse (lineItem.GetAttribute ("permission_level"), out int permissionLevel)) {
     296                                        Log.Warning (
     297                                                $"Ignoring permission-entry because of invalid (non-numeric) value for 'permission_level' attribute: {subChild.OuterXml}");
     298                                        continue;
     299                                }
     300
     301                                AddModulePermission (lineItem.GetAttribute ("module"), permissionLevel, false);
     302                        }
     303                }
     304
     305                public void Save () {
     306                        XmlDocument xml = new XmlDocument ();
     307
     308                        xml.CreateXmlDeclaration ();
     309
     310                        // xml.AddXmlComment (XmlHeader);
     311
     312                        XmlElement root = xml.AddXmlElement ("webpermissions");
     313
     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 ());
     322                        }
     323
     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                        }
    207330                       
    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 () {
     331
    294332                        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 
     333                        xml.Save (SettingsFullPath);
    342334                        fileWatcher.EnableRaisingEvents = true;
    343335                }
     336
     337#endregion
    344338
    345339
Note: See TracChangeset for help on using the changeset viewer.