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

Last change on this file since 449 was 433, checked in by alloc, 19 months ago

Fixed: User registration allowed same username for multiple users

File size: 5.0 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 WebUser p = new WebUser (_name, _password, _userIdentifier, _crossPlatformIdentifier);
46
47 // TODO: Check if another name exists with the same (crossplatform)identifier, remove that
48 users [_name] = p;
49
50 Parent.Save ();
51 }
52
53 public bool RemoveUser (string _name) {
54 bool removed = users.Remove (_name);
55 if (removed) {
56 Parent.Save ();
57 }
58
59 return removed;
60 }
61
62 public Dictionary<string, WebUser> GetUsers () {
63 return users;
64 }
65
66#endregion
67
68 public readonly struct WebUser {
69 public readonly string Name;
70 public readonly byte[] PasswordHash;
71 public readonly PlatformUserIdentifierAbs PlatformUser;
72 public readonly PlatformUserIdentifierAbs CrossPlatformUser;
73
74 public WebUser (string _name, byte[] _passwordHash, PlatformUserIdentifierAbs _platformUser, PlatformUserIdentifierAbs _crossPlatformUser) {
75 Name = _name;
76 PasswordHash = _passwordHash;
77 PlatformUser = _platformUser;
78 CrossPlatformUser = _crossPlatformUser;
79 }
80
81 public WebUser (string _name, string _password, PlatformUserIdentifierAbs _platformUser, PlatformUserIdentifierAbs _crossPlatformUser) {
82 Name = _name;
83 PasswordHash = Hash (_password);
84 PlatformUser = _platformUser;
85 CrossPlatformUser = _crossPlatformUser;
86 }
87
88 public void ToXml (XmlElement _parent) {
89 XmlElement elem = _parent.AddXmlElement ("user");
90 elem.SetAttrib ("name", Name)
91 .SetAttrib ("pass", Convert.ToBase64String(PasswordHash));
92 PlatformUser.ToXml (elem);
93 CrossPlatformUser?.ToXml (elem, "cross");
94 }
95
96 public static bool TryParse (XmlElement _element, out WebUser _result) {
97 _result = default;
98
99 if (!_element.TryGetAttribute ("name", out string name)) {
100 Log.Warning ($"[Web] [Perms] Ignoring user-entry because of missing 'name' attribute: {_element.OuterXml}");
101 return false;
102 }
103
104 if (!_element.TryGetAttribute ("pass", out string passHashString)) {
105 Log.Warning ($"[Web] [Perms] Ignoring user-entry because of missing 'pass' attribute: {_element.OuterXml}");
106 return false;
107 }
108
109 PlatformUserIdentifierAbs userIdentifier = PlatformUserIdentifierAbs.FromXml (_element, false);
110 if (userIdentifier == null) {
111 Log.Warning ($"[Web] [Perms] Ignoring user-entry because of missing 'platform' or 'userid' attribute: {_element.OuterXml}");
112 return false;
113 }
114
115 PlatformUserIdentifierAbs crossIdentifier = PlatformUserIdentifierAbs.FromXml (_element, false, "cross");
116
117 byte[] passHash = Convert.FromBase64String (passHashString);
118
119 _result = new WebUser (name, passHash, userIdentifier, crossIdentifier);
120 return true;
121 }
122
123 public bool ValidatePassword (string _password) {
124 byte[] input = Hash (_password);
125 return Utils.ArrayEquals (input, PasswordHash);
126 }
127 }
128
129 private static byte[] Hash (string _input) {
130 System.Security.Cryptography.MD5Cng hasherMD5 = new System.Security.Cryptography.MD5Cng();
131
132 return hasherMD5.ComputeHash (Encoding.UTF8.GetBytes (_input));
133 }
134
135 public bool TryGetUser (string _name, string _password, out WebUser _result) {
136 if (users.TryGetValue (_name, out _result) && _result.ValidatePassword (_password)) {
137 return true;
138 }
139
140 _result = default;
141 return false;
142 }
143
144 public bool HasUser (PlatformUserIdentifierAbs _platformUser, PlatformUserIdentifierAbs _crossPlatformUser, out WebUser _result) {
145 _result = default;
146
147 foreach ((string _, WebUser webUser) in users) {
148 if (!PlatformUserIdentifierAbs.Equals (webUser.PlatformUser, _platformUser) ||
149 !PlatformUserIdentifierAbs.Equals (webUser.CrossPlatformUser, _crossPlatformUser)) {
150 continue;
151 }
152
153 _result = webUser;
154 return true;
155 }
156
157 return false;
158 }
159
160 }
161}
Note: See TracBrowser for help on using the repository browser.