diff options
author | onefang | 2019-08-17 07:09:16 +1000 |
---|---|---|
committer | onefang | 2019-08-17 07:09:16 +1000 |
commit | ee33dd4b56f7782bbf7798fa3ff8821ff81acd36 (patch) | |
tree | 591ed389ce4daf085a2ed79b2e9fc26957c9c476 /OpenSim | |
parent | Simple web server gets HTTPS. (diff) | |
download | opensim-SC_OLD-ee33dd4b56f7782bbf7798fa3ff8821ff81acd36.zip opensim-SC_OLD-ee33dd4b56f7782bbf7798fa3ff8821ff81acd36.tar.gz opensim-SC_OLD-ee33dd4b56f7782bbf7798fa3ff8821ff81acd36.tar.bz2 opensim-SC_OLD-ee33dd4b56f7782bbf7798fa3ff8821ff81acd36.tar.xz |
VArious additions to account manager.
First and last names merged into one name.
Is name two words check, a suprisingly effective spam blocker.
Poor mans Bobby Tables protection.
Various other input checking.
Added account creation confirmation page.
Some text and length tweaks.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Server/Handlers/Web/WebServerConnector.cs | 102 |
1 files changed, 83 insertions, 19 deletions
diff --git a/OpenSim/Server/Handlers/Web/WebServerConnector.cs b/OpenSim/Server/Handlers/Web/WebServerConnector.cs index 3a8e906..7879e4e 100644 --- a/OpenSim/Server/Handlers/Web/WebServerConnector.cs +++ b/OpenSim/Server/Handlers/Web/WebServerConnector.cs | |||
@@ -6,6 +6,7 @@ using System.Net; | |||
6 | using System.Reflection; | 6 | using System.Reflection; |
7 | using System.Security; | 7 | using System.Security; |
8 | using System.Text; | 8 | using System.Text; |
9 | using System.Text.RegularExpressions; | ||
9 | using log4net; | 10 | using log4net; |
10 | using Nini.Config; | 11 | using Nini.Config; |
11 | using OpenMetaverse; | 12 | using OpenMetaverse; |
@@ -131,13 +132,14 @@ namespace OpenSim.Server.Handlers.Web | |||
131 | return reply; | 132 | return reply; |
132 | } | 133 | } |
133 | 134 | ||
134 | m_log.InfoFormat("[WEB SERVICE]: {0} method path {1} type {2} body {3}.", method, reqpath, type, body); | 135 | m_log.InfoFormat("[WEB SERVICE]: {0} method path {1} contont type {2} body {3}.", method, reqpath, type, body); |
135 | foreach (DictionaryEntry h in headers) | 136 | foreach (DictionaryEntry h in headers) |
136 | m_log.InfoFormat("[WEB SERVICE]: {0} method path {1} header {2} = {3}", method, reqpath, (string) h.Key, (string) h.Value); | 137 | m_log.InfoFormat("[WEB SERVICE]: {0} method path {1} header {2} = {3}", method, reqpath, (string) h.Key, (string) h.Value); |
137 | foreach (String q in query) | 138 | foreach (String q in query) |
138 | m_log.InfoFormat("[WEB SERVICE]: {0} method path {1} query {2} value {3}", method, reqpath, q, (string) request[q]); | 139 | m_log.InfoFormat("[WEB SERVICE]: {0} method path {1} query {2} value {3}", method, reqpath, q, (string) request[q]); |
139 | 140 | ||
140 | reply["int_response_code"] = 200; | 141 | reply["int_response_code"] = 200; |
142 | // TODO - need to support HEAD method, seems to be what triggers the endles GETs. | ||
141 | if ("GET" == method) | 143 | if ("GET" == method) |
142 | { | 144 | { |
143 | if (File.Exists(path)) | 145 | if (File.Exists(path)) |
@@ -211,25 +213,71 @@ namespace OpenSim.Server.Handlers.Web | |||
211 | String v = ""; | 213 | String v = ""; |
212 | if (b.Length > 1) | 214 | if (b.Length > 1) |
213 | v = System.Web.HttpUtility.UrlDecode(b[1]); | 215 | v = System.Web.HttpUtility.UrlDecode(b[1]); |
216 | if ((0 != String.Compare("password", n)) && (0 != String.Compare("psswrd", n))) | ||
217 | { | ||
218 | // Poor mans Bobby Tables protection. | ||
219 | v = v.Replace("'", "_"); | ||
220 | v = v.Replace("\"", "_"); | ||
221 | v = v.Replace(";", "_"); | ||
222 | v = v.Replace("(", "_"); | ||
223 | v = v.Replace(")", "_"); | ||
224 | } | ||
214 | fields[n] = v; | 225 | fields[n] = v; |
215 | body = body + "<p>" + n + " = " + v + "</p>\n"; | 226 | body = body + "<p>" + n + " = " + v + "</p>\n"; |
216 | } | 227 | } |
217 | 228 | ||
218 | if ("account.html" == file) | 229 | if ("account.html" == file) |
219 | { | 230 | { |
231 | string doit = fields["doit"].ToString(); | ||
220 | replyHeaders["Cache-Control"] = "no-cache"; | 232 | replyHeaders["Cache-Control"] = "no-cache"; |
221 | if ("logout" == fields["doit"].ToString()) | 233 | if ("logout" == doit) |
222 | reply["str_response_string"] = loginPage(null, "Logged out."); | 234 | reply["str_response_string"] = loginPage(null, "Logged out."); |
223 | else if ("create" == fields["doit"].ToString()) | 235 | else if (("create" == doit) || ("confirm" == doit)) |
224 | { | 236 | { |
237 | Regex rgxName = new Regex("^[a-zA-Z0-9]+$"); | ||
238 | Regex rgxEmail = new Regex("^.+@.+\\..+$"); | ||
239 | string[] names = fields["name"].ToString().Split(' '); | ||
225 | if ("" == fields["email"].ToString()) | 240 | if ("" == fields["email"].ToString()) |
226 | reply["str_response_string"] = loginPage(fields, "Please supply an email address when creating an account."); | 241 | reply["str_response_string"] = loginPage(fields, "Please supply an email address when creating an account."); |
242 | else if (!rgxEmail.IsMatch(fields["email"].ToString())) | ||
243 | reply["str_response_string"] = loginPage(fields, "Please supply a valid email address when creating an account."); | ||
244 | else if (!Uri.IsWellFormedUriString("mailto:" + fields["email"].ToString(), System.UriKind.Absolute)) | ||
245 | reply["str_response_string"] = loginPage(fields, "Please supply a valid email address when creating an account."); | ||
246 | // TODO - the other test to do here is actually lookup the domain name, looking for any sort of record. | ||
247 | else if (2 != names.Length) | ||
248 | reply["str_response_string"] = loginPage(fields, "Please supply a two word name when creating an account."); | ||
249 | // SL docs say 31 characters each for first and last name. UserAccounts table is varchar(64) each. userinfo has varchar(50) for the combined name. | ||
250 | // The userinfo table seems to be obsolete. | ||
251 | // Singularity at least limits the total name to 64. | ||
252 | // I can't find any limitations on characters allowed, but I only ever see letters and digits used. Case is stored, but not significant. | ||
253 | // OpenSims "create user" console command doesn't sanitize it at all, even crashing on some names. | ||
254 | else if (31 < names[0].Length) | ||
255 | reply["str_response_string"] = loginPage(fields, "First and last names are limited to 31 letters each."); | ||
256 | else if (31 < names[1].Length) | ||
257 | reply["str_response_string"] = loginPage(fields, "First and last names are limited to 31 letters each."); | ||
258 | else if (!rgxName.IsMatch(names[0])) | ||
259 | reply["str_response_string"] = loginPage(fields, "First and last names are limited to letters and digits."); | ||
260 | else if (!rgxName.IsMatch(names[1])) | ||
261 | reply["str_response_string"] = loginPage(fields, "First and last names are limited to letters and digits."); | ||
262 | // TODO - check and disallow god names, those are done in the console. | ||
227 | else | 263 | else |
228 | { | 264 | { |
229 | reply["str_response_string"] = loggedOnPage(body, fields); | 265 | if (("create" == doit)) |
266 | reply["str_response_string"] = accountCreationPage(body, fields); | ||
267 | else | ||
268 | { | ||
269 | if (0 != String.Compare(fields["psswrd"].ToString(), fields["password"].ToString())) | ||
270 | reply["str_response_string"] = loginPage(fields, "Passwords are not the same."); | ||
271 | else | ||
272 | reply["str_response_string"] = loggedOnPage(body, fields); | ||
273 | } | ||
230 | } | 274 | } |
231 | } | 275 | } |
232 | else if ("list" == fields["doit"].ToString()) | 276 | else if ("cancel" == doit) |
277 | { | ||
278 | reply["str_response_string"] = loginPage(null, "Cancelled."); | ||
279 | } | ||
280 | else if ("list" == doit) | ||
233 | { | 281 | { |
234 | List< Hashtable > rows = m_database.Select("UserAccounts", | 282 | List< Hashtable > rows = m_database.Select("UserAccounts", |
235 | "CONCAT(FirstName,' ',LastName) as Name,UserTitle as Title,UserLevel as Level,UserFlags as Flags,PrincipalID as UUID", | 283 | "CONCAT(FirstName,' ',LastName) as Name,UserTitle as Title,UserLevel as Level,UserFlags as Flags,PrincipalID as UUID", |
@@ -268,21 +316,19 @@ namespace OpenSim.Server.Handlers.Web | |||
268 | 316 | ||
269 | private string loginPage(Hashtable fields, string message) | 317 | private string loginPage(Hashtable fields, string message) |
270 | { | 318 | { |
271 | string f = ""; | 319 | string n = ""; |
272 | string l = ""; | ||
273 | string e = ""; | 320 | string e = ""; |
274 | if (null != fields) | 321 | if (null != fields) |
275 | { | 322 | { |
276 | f = fields["firstName"].ToString(); | 323 | n = fields["name"].ToString(); |
277 | l = fields["lastName"].ToString(); | ||
278 | e = fields["email"].ToString(); | 324 | e = fields["email"].ToString(); |
279 | } | 325 | } |
280 | return header(ssi["grid"] + " account") | 326 | return header(ssi["grid"] + " account") |
281 | + form("account.html", "", | 327 | + form("account.html", "", |
282 | text("text", "first name", "firstName", f, 16, true) | 328 | text("text", "name", "name", n, 63, true) |
283 | + text("text", "last name", "lastName", l, 16, true) | 329 | + text("email", "email", "email", e, 254, false) |
284 | + text("email", "email", "email", e, 0, false) | 330 | + text("password", "password", "password", "", 0, true) |
285 | + text("password", "password", "password", "", 14,true) | 331 | + "Warning, the limit on password length is set by your viewer, some can't handle longer than 16 characters." |
286 | + button("create") | 332 | + button("create") |
287 | + button("login") | 333 | + button("login") |
288 | ) | 334 | ) |
@@ -290,17 +336,35 @@ namespace OpenSim.Server.Handlers.Web | |||
290 | + footer(); | 336 | + footer(); |
291 | } | 337 | } |
292 | 338 | ||
339 | private string accountCreationPage(string body, Hashtable fields) | ||
340 | { | ||
341 | return header(ssi["grid"] + " account") | ||
342 | + "<h1>Creating " + ssi["grid"] + " account for " + fields["name"].ToString() + "</h1>" | ||
343 | + form("account.html", fields["token"].ToString(), | ||
344 | hidden("name", fields["name"].ToString()) | ||
345 | + hidden("psswrd", fields["password"].ToString()) | ||
346 | + text("email", "An email will be sent to", "email", fields["email"].ToString(), 254, true) | ||
347 | + " to validate it, please double check this." | ||
348 | + text("password", "Re-enter your password", "password", "", 0, true) | ||
349 | + "Warning, the limit on password length is set by your viewer, some can't handle longer than 16 characters." | ||
350 | + button("confirm") | ||
351 | + button("cancel") | ||
352 | ) | ||
353 | + body | ||
354 | + footer(); | ||
355 | } | ||
356 | |||
293 | private string loggedOnPage(string body, Hashtable fields) | 357 | private string loggedOnPage(string body, Hashtable fields) |
294 | { | 358 | { |
295 | return header(ssi["grid"] + " account") | 359 | return header(ssi["grid"] + " account") |
296 | + "<h1>" + ssi["grid"] + " account for " + fields["firstName"].ToString() + " " + fields["lastName"].ToString() + "</h1>" | 360 | + "<h1>" + ssi["grid"] + " account for " + fields["name"].ToString() + "</h1>" |
297 | + form("account.html", fields["token"].ToString(), | 361 | + form("account.html", fields["token"].ToString(), |
298 | hidden("firstName", fields["firstName"].ToString()) | 362 | hidden("name", fields["name"].ToString()) |
299 | + hidden("lastName", fields["lastName"].ToString()) | ||
300 | // + hidden("UUID", fields["UUID"].ToString()) | 363 | // + hidden("UUID", fields["UUID"].ToString()) |
301 | + text("email", "email", "email", fields["email"].ToString(), 0, false) | 364 | + text("email", "email", "email", fields["email"].ToString(), 254, true) |
302 | + text("password", "password", "password", "", 14, false) | 365 | + text("password", "password", "password", "", 0, false) |
303 | // + text("title", "text", "title", fields["title"].ToString(), 0, false) | 366 | + "Warning, the limit on password length is set by your viewer, some can't handle longer than 16 characters." |
367 | // + text("title", "text", "title", fields["title"].ToString(), 64, false) | ||
304 | + select("type", "type", | 368 | + select("type", "type", |
305 | option("", false) | 369 | option("", false) |
306 | + option("approved", true) | 370 | + option("approved", true) |