using System; using System.Collections.Generic; using System.Net; using System.Text; using System.Text.RegularExpressions; using JetBrains.Annotations; using Utf8Json; using Webserver.Permissions; using Webserver.UrlHandlers; namespace Webserver.WebAPI.APIs { [UsedImplicitly] public class RegisterUser : AbsRestApi { private static readonly byte[] jsonPlayerNameKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("playerName"); private static readonly byte[] jsonExpirationKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("expirationSeconds"); // TODO: Rate-limiting private static readonly Regex userValidationRegex = new Regex ("^\\w{4,16}$", RegexOptions.ECMAScript | RegexOptions.Compiled); private static readonly Regex passValidationRegex = new Regex ("^\\w{4,16}$", RegexOptions.ECMAScript | RegexOptions.Compiled); public RegisterUser (Web _parentWeb) : base (_parentWeb) { } protected override void HandleRestGet (RequestContext _context) { string token = _context.RequestPath; if (string.IsNullOrEmpty (token)) { SendErrorResult (_context, HttpStatusCode.BadRequest, null, "NO_TOKEN"); return; } if (!UserRegistrationTokens.TryValidate (token, out UserRegistrationTokens.RegistrationData regData)) { SendErrorResult (_context, HttpStatusCode.NotFound, null, "INVALID_OR_EXPIRED_TOKEN"); return; } PrepareEnvelopedResult (out JsonWriter writer); writer.WriteRaw (jsonPlayerNameKey); writer.WriteString (regData.PlayerName); writer.WriteRaw (jsonExpirationKey); writer.WriteDouble ((regData.ExpiryTime - DateTime.Now).TotalSeconds); writer.WriteEndObject (); SendEnvelopedResult (_context, ref writer); } protected override void HandleRestPost (RequestContext _context, IDictionary _jsonInput, byte[] _jsonInputData) { if (!TryGetJsonField (_jsonInput, "token", out string token)) { SendErrorResult (_context, HttpStatusCode.BadRequest, _jsonInputData, "MISSING_TOKEN"); return; } if (!TryGetJsonField (_jsonInput, "username", out string username)) { SendErrorResult (_context, HttpStatusCode.BadRequest, _jsonInputData, "MISSING_USERNAME"); return; } if (!TryGetJsonField (_jsonInput, "password", out string password)) { SendErrorResult (_context, HttpStatusCode.BadRequest, _jsonInputData, "MISSING_PASSWORD"); return; } if (!UserRegistrationTokens.TryValidate (token, out UserRegistrationTokens.RegistrationData regData)) { SendErrorResult (_context, HttpStatusCode.Unauthorized, null, "INVALID_OR_EXPIRED_TOKEN"); return; } if (!userValidationRegex.IsMatch (username)) { SendErrorResult (_context, HttpStatusCode.Unauthorized, _jsonInputData, "INVALID_USERNAME"); return; } if (!passValidationRegex.IsMatch (password)) { SendErrorResult (_context, HttpStatusCode.Unauthorized, _jsonInputData, "INVALID_PASSWORD"); return; } // TODO: Check if username is already used by someone else! // TODO: Remove existing username if player already had one! AdminWebUsers.Instance.AddUser (username, password, regData.PlatformUserId, regData.CrossPlatformUserId); string remoteEndpointString = _context.Request.RemoteEndPoint!.ToString (); SessionHandler.HandleUserIdLogin (ParentWeb.ConnectionHandler, _context, remoteEndpointString, SessionHandler.userPassLoginName, SessionHandler.userPassErrorPage, username, regData.PlatformUserId, regData.CrossPlatformUserId, false); _context.Response.StatusCode = (int)HttpStatusCode.Created; _context.Response.ContentType = WebUtils.MimePlain; _context.Response.ContentEncoding = Encoding.UTF8; _context.Response.ContentLength64 = 0; // _context.Response.OutputStream.Write (jsonData.Array!, 0, jsonData.Count); } public override int DefaultPermissionLevel () => AdminWebModules.PermissionLevelGuest; } }