Main.cs 14.9 KB
Newer Older
Logan Kramer's avatar
Logan Kramer committed
1 2
using System;
using System.Collections.Generic;
3
using System.Collections.Concurrent;
Simon311's avatar
Simon311 committed
4
using System.Text.RegularExpressions;
Simon311's avatar
Simon311 committed
5
using System.Reflection;
Simon311's avatar
Simon311 committed
6
using System.Linq;
Logan Kramer's avatar
Logan Kramer committed
7 8 9
using Terraria;
using TerrariaApi.Server;
using TShockAPI;
10
using TShockAPI.DB;
Logan Kramer's avatar
Logan Kramer committed
11
using System.Net;
12 13
using System.IO;
using System.Security.Cryptography;
Logan Kramer's avatar
Logan Kramer committed
14 15 16

namespace TSWVote
{
17
	[ApiVersion(2, 1)]
Simon311's avatar
Simon311 committed
18 19 20 21
	public class TSWVote : TerrariaPlugin
	{
		public override string Name
		{
Simon311's avatar
Simon311 committed
22
			get { return "TServerWebVote"; }
Simon311's avatar
Simon311 committed
23 24 25 26
		}

		public override string Author
		{
Simon311's avatar
Simon311 committed
27
			get { return "Community"; }
Simon311's avatar
Simon311 committed
28 29 30 31
		}

		public override string Description
		{
Simon311's avatar
Simon311 committed
32
			get { return "A plugin to vote to TServerWeb in-game."; }
Simon311's avatar
Simon311 committed
33 34 35 36
		}

		public override Version Version
		{
Simon311's avatar
Simon311 committed
37
			get { return Assembly.GetExecutingAssembly().GetName().Version; }
Simon311's avatar
Simon311 committed
38 39
		}

Simon311's avatar
Simon311 committed
40 41 42 43 44 45
		private Dictionary<string, VoteIP> IPs = new Dictionary<string, VoteIP>();

		private ConcurrentQueue<VoteWC> webClientQueue;

		internal static Config TSWConfig { get; private set; }

Simon311's avatar
Simon311 committed
46 47 48 49
		public TSWVote(Main game)
			: base(game)
		{
			Order = 1000;
Simon311's avatar
Simon311 committed
50
			WebRequest.DefaultWebProxy = null;
51

Simon311's avatar
Simon311 committed
52 53
			TSWConfig = Config.Read();

54
			webClientQueue = new ConcurrentQueue<VoteWC>();
Simon311's avatar
Simon311 committed
55
			for (int i = 0; i < TSWConfig.NumberOfWebClients; i++)
56
			{
57
				VoteWC webClient = new VoteWC();
58 59 60
				webClient.DownloadStringCompleted += WebClient_DownloadStringCompleted;
				webClientQueue.Enqueue(webClient);
            }
Simon311's avatar
Simon311 committed
61 62 63 64
		}

		public override void Initialize()
		{
65 66
			ServerApi.Hooks.GameInitialize.Register(this, OnInitialize, -1);
			ServerApi.Hooks.ServerChat.Register(this, OnChat, 1000);
Simon311's avatar
Simon311 committed
67 68 69 70 71 72 73 74 75
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				ServerApi.Hooks.GameInitialize.Deregister(this, OnInitialize);
				ServerApi.Hooks.ServerChat.Deregister(this, OnChat);

76
				if (webClientQueue != null)
Simon311's avatar
Simon311 committed
77
				{
78 79 80 81 82 83
					VoteWC webClient;
					while (this.webClientQueue.TryDequeue(out webClient))
					{
						webClient.DownloadStringCompleted -= WebClient_DownloadStringCompleted;
						webClient.Dispose();
					}
Simon311's avatar
Simon311 committed
84
				}
85
				 
Simon311's avatar
Simon311 committed
86 87 88 89 90 91
			}
			base.Dispose(disposing);
		}

		private void OnChat(ServerChatEventArgs args)
		{
Simon311's avatar
Simon311 committed
92
			if (!args.Text.StartsWith("/vote"))
93
			{
Simon311's avatar
Simon311 committed
94
				return;
95
			}
Simon311's avatar
Simon311 committed
96

Simon311's avatar
Simon311 committed
97
			var player = TShock.Players[args.Who];
Simon311's avatar
Simon311 committed
98

Simon311's avatar
Simon311 committed
99 100
			if (player == null)
			{
Simon311's avatar
Simon311 committed
101
				args.Handled = true;
Simon311's avatar
Simon311 committed
102 103
				return;
			}
Simon311's avatar
Simon311 committed
104

Simon311's avatar
Simon311 committed
105
			Match M = Regex.Match(args.Text, "^/vote(?: (.*))?$", RegexOptions.IgnoreCase);
Simon311's avatar
Simon311 committed
106
			if (M.Success)
Simon311's avatar
Simon311 committed
107
			{
Simon311's avatar
Simon311 committed
108 109 110 111 112 113
				if (TSWConfig.RequirePermission && !player.Group.HasPermission(TSWConfig.PermissionName))
				{
					player.SendSuccessMessage("[TServerWeb] You don't have permission to vote!");
					return;
				}

Simon311's avatar
Simon311 committed
114
				CommandArgs e = new CommandArgs(args.Text, player, new List<string>());
Simon311's avatar
Simon311 committed
115
				string Args = M.Groups[1].Value;
Simon311's avatar
Simon311 committed
116

117 118 119 120
				if (!IPs.ContainsKey(player.IP))
				{
					IPs.Add(player.IP, new VoteIP(DateTime.Now));
				}
Simon311's avatar
Simon311 committed
121

Simon311's avatar
Simon311 committed
122
				if (!string.IsNullOrWhiteSpace(Args))
Simon311's avatar
Simon311 committed
123
				{
Simon311's avatar
Simon311 committed
124 125 126
					e.Parameters.Add(Args);
					TSPlayer.Server.SendMessage(player.Name + " has entered /vote captcha.", 255, 255, 255);
					Vote(e);
Simon311's avatar
Simon311 committed
127
					args.Handled = true;
Simon311's avatar
Simon311 committed
128
					return;
Simon311's avatar
Simon311 committed
129
				}
Simon311's avatar
Simon311 committed
130 131 132 133

				TSPlayer.Server.SendMessage(player.Name + " executed: /vote.", 255, 255, 255);
				Vote(e);
				args.Handled = true;
Simon311's avatar
Simon311 committed
134 135 136 137 138
			}
		}

		private void OnInitialize(EventArgs args)
		{
Simon311's avatar
Simon311 committed
139
			try
Simon311's avatar
Simon311 committed
140
			{
Simon311's avatar
Simon311 committed
141
				TSWConfig = Config.Read();
Simon311's avatar
Simon311 committed
142
			}
Simon311's avatar
Simon311 committed
143
			catch
Simon311's avatar
Simon311 committed
144
			{
Simon311's avatar
Simon311 committed
145 146
				SendError("Config", "Config file is broken! TSWVote plugin will not load!");
				return;
Simon311's avatar
Simon311 committed
147
			}
148

149 150
			if (!GetServerID(out int id, out string message))
			{
Simon311's avatar
Simon311 committed
151
				SendError("Configuration", message);
152
			}
Simon311's avatar
Simon311 committed
153

Simon311's avatar
Simon311 committed
154 155 156
			if (TShock.Config.RestApiEnabled == false)
			{
				SendError("REST API", "REST API Not Enabled! TSWVote plugin will not load!");
157
				return;
Simon311's avatar
Simon311 committed
158
			}
159

Simon311's avatar
Simon311 committed
160 161
			Commands.ChatCommands.Add(new Command(TSWConfig.RequirePermission ? TSWConfig.PermissionName : null, delegate { }, "vote"));
			// ^ We're making sure the command can be seen in /help. It does nothing though.
162

163
			Commands.ChatCommands.Add(new Command(new List<string> { "vote.changeid", "vote.ping" }, ChangeID, "tserverweb"));
164 165

			Commands.ChatCommands.Add(new Command("vote.checkversion", CheckVersion, "tswversioncheck"));
Simon311's avatar
Simon311 committed
166 167

			Commands.ChatCommands.Add(new Command("vote.admin", Clear, "voteclear"));
168 169

			Commands.ChatCommands.Add(new Command("vote.autosetup", AutoSetup, "tswautosetup"));
Simon311's avatar
Simon311 committed
170 171 172 173 174 175 176 177 178 179 180 181
		}

		private void Clear(CommandArgs e)
		{
			if (e.Parameters.Count == 0)
			{
				if (IPs.ContainsKey(e.Player.IP) && IPs[e.Player.IP].State != VoteState.None)
				{
					e.Player.SendSuccessMessage(string.Format("[TServerWeb] Removed state {0} from IP {1} succesfully.", IPs[e.Player.IP].State, e.Player.IP));
					IPs.Remove(e.Player.IP);
				}
				else
182
				{
Simon311's avatar
Simon311 committed
183
					e.Player.SendSuccessMessage(string.Format("[TServerWeb] No state for IP {0} found.", e.Player.IP));
184
				}
Simon311's avatar
Simon311 committed
185 186 187
				return;
			}

Simon311's avatar
Simon311 committed
188
			string Target = string.Join(" ", e.Parameters).ToLower();
Simon311's avatar
Simon311 committed
189 190 191 192 193

			if (Target == "all")
			{
				IPs.Clear();
				e.Player.SendSuccessMessage("[TServerWeb] Reset all votestates!");
Simon311's avatar
Simon311 committed
194
				return;
Simon311's avatar
Simon311 committed
195 196
			}

Simon311's avatar
Simon311 committed
197
			List<TSPlayer> Ts = TShock.Players.Where(p => (p != null && p.Active && p.Name.ToLower().StartsWith(Target))).ToList();
Simon311's avatar
Simon311 committed
198 199 200 201

			if (Ts.Count == 0)
			{
				e.Player.SendSuccessMessage("[TServerWeb] No players matched!");
Simon311's avatar
Simon311 committed
202
				return;
Simon311's avatar
Simon311 committed
203 204 205 206 207 208 209 210 211 212 213 214
			}

			if (Ts.Count == 1)
			{
				TSPlayer T = Ts[0];

				if (IPs.ContainsKey(T.IP) && IPs[T.IP].State != VoteState.None)
				{
					e.Player.SendSuccessMessage(string.Format("[TServerWeb] Removed state {0} from IP {1} succesfully.", IPs[T.IP].State, T.IP));
					IPs.Remove(T.IP);
				}
				else
215
				{
Simon311's avatar
Simon311 committed
216
					e.Player.SendSuccessMessage(string.Format("[TServerWeb] No state for IP {0} found.", T.IP));
217
				}
Simon311's avatar
Simon311 committed
218

Simon311's avatar
Simon311 committed
219 220 221 222 223
				return;
			}
			
			string TNames = string.Join(", ", Ts.Select(p => p.Name));
			e.Player.SendSuccessMessage(string.Format("[TServerWeb] Matched multiple players: {0}.", TNames));
Simon311's avatar
Simon311 committed
224 225 226 227 228 229 230
		}

		private void CheckVersion(CommandArgs e)
		{
			e.Player.SendInfoMessage(Version.ToString());
		}

Simon311's avatar
Simon311 committed
231
		private bool tswQuery(string url, object userToken = null)
Simon311's avatar
Simon311 committed
232 233
		{
			Uri uri = new Uri("http://www.tserverweb.com/vote.php?" + url);
234 235 236 237 238 239 240 241

			VoteWC webClient;
			if (this.webClientQueue.TryDequeue(out webClient))
			{
				webClient.DownloadStringAsync(uri, userToken);
				return true;
			}
			return false;
Simon311's avatar
Simon311 committed
242 243 244 245
		}

		private void validateCAPTCHA(CommandArgs e)
		{
246 247 248 249
			if (!IPs.ContainsKey(e.Player.IP))
			{
				IPs[e.Player.IP] = new VoteIP(DateTime.Now);
			}
Simon311's avatar
Simon311 committed
250 251
			VoteIP IP = IPs[e.Player.IP];

Simon311's avatar
Simon311 committed
252 253
			if (IP.State != VoteState.Captcha)
			{
Simon311's avatar
Simon311 committed
254
				e.Player.SendSuccessMessage("[TServerWeb] We're not awaiting CAPTCHA from you, do /vote first.");
Simon311's avatar
Simon311 committed
255 256
				return;
			}
Simon311's avatar
Simon311 committed
257

258
			if (!GetServerID(out int id, out string message))
Simon311's avatar
Simon311 committed
259
			{
260
				Fail("Configuration", message, e.Player, IP);
Simon311's avatar
Simon311 committed
261 262 263
				return;
			}

Simon311's avatar
Simon311 committed
264 265
			string answer = Uri.EscapeDataString(e.Parameters[0].ToString());
			string playerName = Uri.EscapeDataString(e.Player.Name);
266

Simon311's avatar
Simon311 committed
267
			string url = string.Format("answer={0}&user={1}&sid={2}", answer, playerName, id);
Simon311's avatar
Simon311 committed
268 269 270 271 272 273 274 275 276

			try
			{
				tswQuery(url, e);
			}
			catch (Exception ex)
			{
				Fail("validateCaptcha", "Attempt to send the query threw an exception: " + ex.Message, e.Player, IP);
			}
Simon311's avatar
Simon311 committed
277 278
		}

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
		private void AutoSetup(CommandArgs e)
		{
			if (TShock.Groups.GroupExists("tserverweb"))
			{
				e.Player.SendInfoMessage("It seems you've already set things up. Group \"tserverweb\" exists!");
				return;
			}

			try
			{
				TShock.Groups.AddGroup("tserverweb", null,
					"tshock.rest.useapi,tshock.rest.users.info,tshock.rest.command,vote.ping",
					TShockAPI.Group.defaultChatColor);

				string userpassword;
				string resttoken;
				string postfix;
				using (RandomNumberGenerator rng = new RNGCryptoServiceProvider())
				{
					byte[] randomData = new byte[36];
					rng.GetBytes(randomData);
					userpassword = RandomTools.GetPasswordFromBytes(randomData, 0, 16);
					resttoken = RandomTools.GetPasswordFromBytes(randomData, 16, 16);
					postfix = RandomTools.GetPasswordFromBytes(randomData, 32, 4);
				}

				var tswuser = new User();
				tswuser.Name = "tserverweb" + postfix;
				tswuser.CreateBCryptHash(userpassword);
				tswuser.Group = "tserverweb";
				TShock.Users.AddUser(tswuser);

				TShock.Config.ApplicationRestTokens.Add(resttoken, new Rests.SecureRest.TokenData() { Username = tswuser.Name, UserGroupName = tswuser.Group });
				TShock.Config.Write(Path.Combine(TShock.SavePath, "config.json"));

				File.WriteAllText(Path.Combine(TShock.SavePath, "tswtoken.txt"), resttoken);

				e.Player.SendSuccessMessage("Autosetup complete! You will find the TServerWeb REST token in tshock/tswtoken.txt.");
				e.Player.SendInfoMessage("You will have to restart your server before REST changes take effect!");
			}
			catch (Exception E)
			{
				e.Player.SendErrorMessage("Something went wrong with autosetup, sorry. Check your console or logs.");
				TShock.Log.ConsoleError(E.ToString());
			}
		}

Simon311's avatar
Simon311 committed
326 327
		private void doVote(CommandArgs e)
		{
328 329 330 331
			if (!IPs.ContainsKey(e.Player.IP))
			{
				IPs[e.Player.IP] = new VoteIP(DateTime.Now);
			}
Simon311's avatar
Simon311 committed
332 333 334 335 336 337 338 339
			VoteIP IP = IPs[e.Player.IP];

			if (!IP.CanVote())
			{
				IP.NotifyPlayer(e.Player);
				return;
			}

340
			if (!GetServerID(out int id, out string message))
Simon311's avatar
Simon311 committed
341
			{
342
				Fail("Configuration", message, e.Player, IP);
Simon311's avatar
Simon311 committed
343 344
				return;
			}
345

Simon311's avatar
Simon311 committed
346 347
			IP.State = VoteState.InProgress;
			IP.StateTime = DateTime.Now;
Simon311's avatar
Simon311 committed
348
			string url = string.Format("user={0}&sid={1}", Uri.EscapeDataString(e.Player.Name), id);
Simon311's avatar
Simon311 committed
349 350 351 352 353 354 355 356 357

			try
			{
				tswQuery(url, e);
			}
			catch (Exception ex)
			{
				Fail("doVote", "Attempt to send the query threw an exception: " + ex.Message, e.Player, IP);
			}
Simon311's avatar
Simon311 committed
358 359 360 361 362 363 364
		}

		private void Vote(CommandArgs e) // To be fair this should also have a permission.
		{
			try
			{
				if (e.Parameters.Count == 0)
Simon311's avatar
Simon311 committed
365
					doVote(e); // Send the vote
Simon311's avatar
Simon311 committed
366
				else
Simon311's avatar
Simon311 committed
367
					validateCAPTCHA(e); // Answer was provided
Simon311's avatar
Simon311 committed
368 369 370
			}
			catch (Exception ex)
			{
371
				Fail("Vote", "Connection failure: " + ex, e.Player);
Simon311's avatar
Simon311 committed
372 373 374 375 376 377 378
			}
		}

		private void ChangeID(CommandArgs e)
		{
			if (e.Parameters.Count == 0)
			{
379
				if (!GetServerID(out int id, out string message))
Simon311's avatar
Simon311 committed
380
				{
Simon311's avatar
Simon311 committed
381
					e.Player.SendErrorMessage("[TServerWeb] Server ID is currently not specified! Please type /tserverweb [number] to set it.");
Simon311's avatar
Simon311 committed
382 383 384 385 386 387 388 389 390 391 392 393 394
					return;
				}

				e.Player.SendInfoMessage("[TServerWeb] Server ID is currently set to " + id + ". Type /tserverweb [number] to change it.");
				return;
			}

			if (e.Parameters.Count >= 2)
			{
				e.Player.SendErrorMessage("[TServerWeb] Incorrect syntax! Correct syntax: /tserverweb [number]");
				return;
			}

395 396 397 398 399 400 401
			if (!e.Player.HasPermission("vote.changeid"))
			{
				e.Player.SendSuccessMessage("[TServerWeb] Pong!");
				return;
			}

			if (int.TryParse(e.Parameters[0], out int newId))
Simon311's avatar
Simon311 committed
402
			{
Simon311's avatar
Simon311 committed
403 404
				TSWConfig.ServerID = newId;
				TSWConfig.Write();
Simon311's avatar
Simon311 committed
405 406 407 408 409 410 411 412 413 414

				e.Player.SendInfoMessage("[TServerWeb] Server ID successfully changed to " + newId + "!");
				return;
			}

			e.Player.SendErrorMessage("[TServerWeb] Number not specified! Please type /tserverweb [number]");
		}

		private void SendError(string typeoffailure, string message)
		{
Simon311's avatar
Simon311 committed
415
			string Error = string.Format("[TServerWeb] TSWVote Error: {0} failure. Reason: {1}", typeoffailure, message);
Simon311's avatar
Simon311 committed
416
			TShock.Log.ConsoleError(Error);
Simon311's avatar
Simon311 committed
417 418 419 420
		}

		private bool GetServerID(out int id, out string message)
		{
Simon311's avatar
Simon311 committed
421 422
			id = TSWConfig.ServerID;
			message = String.Empty;
Simon311's avatar
Simon311 committed
423

Simon311's avatar
Simon311 committed
424 425 426 427
			if (id == 0)
			{
				message = "Server ID not specified. Type /tserverweb [ID] to specify it.";
				return false;
Simon311's avatar
Simon311 committed
428 429
			}

Simon311's avatar
Simon311 committed
430
			return true;
Simon311's avatar
Simon311 committed
431
		}
432

Simon311's avatar
Simon311 committed
433
		private void WebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
Simon311's avatar
Simon311 committed
434
		{
435 436
			VoteWC webClient = sender as VoteWC;

Simon311's avatar
Simon311 committed
437
			CommandArgs args = e.UserState as CommandArgs;
438

Simon311's avatar
Simon311 committed
439
			if (args == null)
440 441
			{
				ReuseWC(webClient);
Simon311's avatar
Simon311 committed
442
				return;
443
			}
Simon311's avatar
Simon311 committed
444

445 446 447 448
			if (!IPs.ContainsKey(args.Player.IP))
			{
				IPs[args.Player.IP] = new VoteIP(DateTime.Now);
			}
Simon311's avatar
Simon311 committed
449 450
			VoteIP IP = IPs[args.Player.IP];

Simon311's avatar
Simon311 committed
451 452
			if (e.Error != null)
			{
453
				Fail("Exception", e.Error.Message, args.Player, IP);
Simon311's avatar
Simon311 committed
454

455
				ReuseWC(webClient);
Simon311's avatar
Simon311 committed
456 457 458 459
				return;
			}

			Response response = Response.Read(e.Result);
460 461
			if (response == null)
			{
462
				Fail("Response", "Invalid response received.", args.Player, IP);
Simon311's avatar
Simon311 committed
463

464 465 466 467
				ReuseWC(webClient);
				return;
			}

Simon311's avatar
Simon311 committed
468 469 470 471 472 473
			switch (response.response)
			{
				case "success":
					// Correct answer was provided
					// This means a vote is placed
					args.Player.SendSuccessMessage("[TServerWeb] " + response.message);
Simon311's avatar
Simon311 committed
474 475 476 477 478 479 480 481 482 483 484
					if (response.message != "Please wait 24 hours before voting for this server again!")
					{
						IP.State = VoteState.Success;
						IP.StateTime = DateTime.Now;
						VoteHooks.InvokeVoteSuccess(args.Player);
					}
					else
					{
						IP.State = VoteState.Wait;
						IP.StateTime = DateTime.Now;
					}
Simon311's avatar
Simon311 committed
485 486
					break;
				case "failure":
487
					Fail("Vote", response.message, args.Player, IP);
Simon311's avatar
Simon311 committed
488 489 490 491 492
					break;
				case "captcha":
					args.Player.SendSuccessMessage("[TServerWeb] Please answer the question to make sure you are human.");
					args.Player.SendSuccessMessage("[TServerWeb] You can type /vote <answer>");
					args.Player.SendSuccessMessage("[TServerWeb] (CAPTCHA) " + response.message);
Simon311's avatar
Simon311 committed
493 494
					IP.State = VoteState.Captcha;
					IP.StateTime = DateTime.Now;
Simon311's avatar
Simon311 committed
495 496 497
					break;
				case "nocaptcha":
					// Answer was provided, but there was no pending captcha
Simon311's avatar
Simon311 committed
498
					// Let's consider it a fail, since plugin has VoteStates to prevent this from happening
499
					Fail("Vote", response.message, args.Player, IP);
Simon311's avatar
Simon311 committed
500 501 502
					break;
				case "captchafail":
					args.Player.SendErrorMessage("[TServerWeb] Vote failed! Reason: " + response.message);
Simon311's avatar
Simon311 committed
503 504
					IP.State = VoteState.None;
					IP.StateTime = DateTime.Now;
Simon311's avatar
Simon311 committed
505 506 507 508
					break;
				case "":
				case null:
				default:
509
					Fail("Connection", "Response is blank, something is wrong with connection. Please email contact@tserverweb.com about this issue.", args.Player, IP);
Simon311's avatar
Simon311 committed
510 511
					break;
			}
512 513 514 515 516 517

			ReuseWC(webClient);
		}

		private void ReuseWC(VoteWC WC)
		{
518 519 520 521
			if (WC == null)
			{
				return;
			}
522
			webClientQueue.Enqueue(WC);
Simon311's avatar
Simon311 committed
523
		}
524

525 526 527
		internal void Fail(string typeoffailure, string message, TSPlayer Player, VoteIP IP = null)
		{
			SendError(typeoffailure, message);
528 529 530 531
			if (Player == null || !Player.Active)
			{
				return;
			}
532
			Player.SendErrorMessage("[TServerWeb] Vote failed! Please contact an administrator.");
533 534 535 536 537
			if (IPs.ContainsKey(Player.IP))
			{
				if (IP == null) IP = IPs[Player.IP];
				IP.Fail();
			}
538 539
		}

540 541
		private class VoteWC : WebClient
		{
Simon311's avatar
Simon311 committed
542 543 544 545 546 547 548
			public static int Timeout
			{
				get
				{
					return TSWConfig == null ? 2000 : TSWConfig.Timeout;
				}
			}
549 550 551 552 553 554

			public VoteWC()
			{
				Proxy = null;
			}

555 556
			protected override WebRequest GetWebRequest(Uri uri)
			{
Simon311's avatar
Simon311 committed
557
				HttpWebRequest w = base.GetWebRequest(uri) as HttpWebRequest;
558
				w.Timeout = Timeout;
Simon311's avatar
Simon311 committed
559
				w.UserAgent = "TServerWeb Vote Plugin";
Simon311's avatar
Simon311 committed
560

561 562 563
				return w;
			}
		}
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586

		internal static class RandomTools
		{
			private static char[] Passchars = new char[]
			{
				'a', 'b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',

				'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',

				'1','2','3','4','5','6','7','8','9','0'
			};

			internal static string GetPasswordFromBytes(byte[] random, int start, int length)
			{
				string password = string.Empty;
				for (int i = start; i < start + length; i++)
				{
					password += Passchars[random[i] % Passchars.Length];
				}

				return password;
			}
		}
Simon311's avatar
Simon311 committed
587
	}
XGhozt's avatar
XGhozt committed
588
}