source: TFP-WebServer/WebServer/src/Permissions/AdminWebUsers.cs@ 474

Last change on this file since 474 was 474, checked in by alloc, 15 months ago

Added locks on AdminTools instead of local to the individual permission systems

File size: 5.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Xml;
5
6namespace Webserver.Permissions {
7 public class AdminWebUsers : AdminSectionAbs {
8 public static AdminWebUsers Instance { get; private set; }
9
10 public AdminWebUsers (AdminTools _parent) : base (_parent, "webusers") {
11 Instance = this;
12 }
13
14 private readonly Dictionary<string, WebUser> users = new CaseInsensitiveStringDictionary<WebUser> ();
15
16
17#region IO
18
19 public override void Clear () {
20 users.Clear ();
21 }
22
23 protected override void ParseElement (XmlElement _childElement) {
24 if (WebUser.TryParse (_childElement, out WebUser webUser)) {
25 users [webUser.Name] = webUser;
26 }
27 }
28
29 public override void Save (XmlElement _root) {
30 XmlElement usersElement = _root.AddXmlElement (SectionTypeName);
31 // modulesElement.AddXmlComment (" <module name=\"adminuser1\" secret=\"supersecrettoken\" permission_level=\"0\" /> ");
32
33 foreach ((string _, WebUser module) in users) {
34 module.ToXml (usersElement);
35 }
36 }
37
38#endregion
39
40
41#region Runtime interaction
42
43
44 public void AddUser (string _name, string _password, PlatformUserIdentifierAbs _userIdentifier, PlatformUserIdentifierAbs _crossPlatformIdentifier) {
45 lock (Parent) {
46 WebUser p = new WebUser (_name, _password, _userIdentifier, _crossPlatformIdentifier);
47
48 // TODO: Check if another name exists with the same (crossplatform)identifier, remove that
49 users[_name] = p;
50
51 Parent.Save ();
52 }
53 }
54
55 public bool RemoveUser (string _name) {
56 lock (Parent) {
57 bool removed = users.Remove (_name);
58 if (removed) {
59 Parent.Save ();
60 }
61
62 return removed;
63 }
64 }
65
66 public Dictionary<string, WebUser> GetUsers () {
67 lock (Parent) {
68 return users;
69 }
70 }
71
72#endregion
73
74 public readonly struct WebUser {
75 public readonly string Name;
76 public readonly byte[] PasswordHash;
77 public readonly PlatformUserIdentifierAbs PlatformUser;
78 public readonly PlatformUserIdentifierAbs CrossPlatformUser;
79
80 public WebUser (string _name, byte[] _passwordHash, PlatformUserIdentifierAbs _platformUser, PlatformUserIdentifierAbs _crossPlatformUser) {
81 Name = _name;
82 PasswordHash = _passwordHash;
83 PlatformUser = _platformUser;
84 CrossPlatformUser = _crossPlatformUser;
85 }
86
87 public WebUser (string _name, string _password, PlatformUserIdentifierAbs _platformUser, PlatformUserIdentifierAbs _crossPlatformUser) {
88 Name = _name;
89 PasswordHash = Hash (_password);
90 PlatformUser = _platformUser;
91 CrossPlatformUser = _crossPlatformUser;
92 }
93
94 public void ToXml (XmlElement _parent) {
95 XmlElement elem = _parent.AddXmlElement ("user");
96 elem.SetAttrib ("name", Name)
97 .SetAttrib ("pass", Convert.ToBase64String(PasswordHash));
98 PlatformUser.ToXml (elem);
99 CrossPlatformUser?.ToXml (elem, "cross");
100 }
101
102 public static bool TryParse (XmlElement _element, out WebUser _result) {
103 _result = default;
104
105 if (!_element.TryGetAttribute ("name", out string name)) {
106 Log.Warning ($"[Web] [Perms] Ignoring user-entry because of missing 'name' attribute: {_element.OuterXml}");
107 return false;
108 }
109
110 if (!_element.TryGetAttribute ("pass", out string passHashString)) {
111 Log.Warning ($"[Web] [Perms] Ignoring user-entry because of missing 'pass' attribute: {_element.OuterXml}");
112 return false;
113 }
114
115 PlatformUserIdentifierAbs userIdentifier = PlatformUserIdentifierAbs.FromXml (_element, false);
116 if (userIdentifier == null) {
117 Log.Warning ($"[Web] [Perms] Ignoring user-entry because of missing 'platform' or 'userid' attribute: {_element.OuterXml}");
118 return false;
119 }
120
121 PlatformUserIdentifierAbs crossIdentifier = PlatformUserIdentifierAbs.FromXml (_element, false, "cross");
122
123 byte[] passHash = Convert.FromBase64String (passHashString);
124
125 _result = new WebUser (name, passHash, userIdentifier, crossIdentifier);
126 return true;
127 }
128
129 public bool ValidatePassword (string _password) {
130 byte[] input = Hash (_password);
131 return Utils.ArrayEquals (input, PasswordHash);
132 }
133 }
134
135 private static byte[] Hash (string _input) {
136 System.Security.Cryptography.MD5Cng hasherMD5 = new System.Security.Cryptography.MD5Cng();
137
138 return hasherMD5.ComputeHash (Encoding.UTF8.GetBytes (_input));
139 }
140
141 public bool TryGetUser (string _name, string _password, out WebUser _result) {
142 lock (Parent) {
143 if (users.TryGetValue (_name, out _result) && _result.ValidatePassword (_password)) {
144 return true;
145 }
146
147 _result = default;
148 return false;
149 }
150 }
151
152 public bool HasUser (PlatformUserIdentifierAbs _platformUser, PlatformUserIdentifierAbs _crossPlatformUser, out WebUser _result) {
153 lock (Parent) {
154 _result = default;
155
156 foreach ((string _, WebUser webUser) in users) {
157 if (!PlatformUserIdentifierAbs.Equals (webUser.PlatformUser, _platformUser) ||
158 !PlatformUserIdentifierAbs.Equals (webUser.CrossPlatformUser, _crossPlatformUser)) {
159 continue;
160 }
161
162 _result = webUser;
163 return true;
164 }
165
166 return false;
167 }
168 }
169
170 }
171}
Note: See TracBrowser for help on using the repository browser.