private void HandleRequest(HttpListenerContext context) { HttpListenerRequest request = context.Request; HttpListenerResponse response = context.Response; Console.WriteLine("Request {0}/{1} from {2}", request.RawUrl.ToString(), request.HttpMethod, request.RemoteEndPoint); try { // Lets figure out the request... switch (request.HttpMethod) { // Sanity check request case "GET": byte[] responseString; //We verifying a password reset token? if (request.Url.AbsolutePath.Contains("verify-token")) { string tokenData = request.QueryString["token"]; response.AppendHeader("Access-Control-Allow-Origin", "*"); response.AppendHeader("Access-Control-Allow-Methods", "POST, GET"); //1. Does the token exist? if (!client.IsTokenValid(tokenData)) { responseString = Encoding.UTF8.GetBytes("false"); response.StatusCode = 404; //Not Found response.ContentLength64 = responseString.Length; response.OutputStream.Write(responseString, 0, responseString.Length); response.OutputStream.Close(); break; } //2. Did the token expire? if (client.TokenExpired(tokenData)) { responseString = Encoding.UTF8.GetBytes("false"); response.StatusCode = 400; //Bad Request response.ContentLength64 = responseString.Length; response.OutputStream.Write(responseString, 0, responseString.Length); response.OutputStream.Close(); break; } //3. Was the token used already? if (client.TokenUsed(tokenData)) { responseString = Encoding.UTF8.GetBytes("false"); response.StatusCode = 409; //Conflict response.ContentLength64 = responseString.Length; response.OutputStream.Write(responseString, 0, responseString.Length); response.OutputStream.Close(); break; } responseString = Encoding.UTF8.GetBytes("true"); response.StatusCode = 200; //Ok response.ContentLength64 = responseString.Length; response.OutputStream.Write(responseString, 0, responseString.Length); response.OutputStream.Close(); break; } //Ping responseString = Encoding.UTF8.GetBytes("Works!"); response.ContentLength64 = responseString.Length; response.OutputStream.Write(responseString, 0, responseString.Length); response.OutputStream.Close(); break; // Account registration request case "PUT": // 1. Is the request good? if (!request.HasEntityBody) { response.StatusCode = 400; //BadRequest response.OutputStream.Close(); break; } string registrationData = new StreamReader(request.InputStream).ReadToEnd(); var regModel = JsonConvert.DeserializeObject <Account.RegistrationRequestModel>(registrationData); // 2. Data valid? if (!regModel.IsRequestValid()) { response.StatusCode = 400; //BadRequest response.OutputStream.Close(); break; } // 3. Is the username available? if (client.UsernameExists(regModel.Username)) { response.StatusCode = 403; //Forbidden response.StatusDescription = "Username already exists."; response.OutputStream.Close(); break; } // 4. Are the credentials good? if (!Account.IsValidUsername(regModel.Username) || !Account.IsValidEmail(regModel.Email)) { response.StatusCode = 406; //Not Acceptable response.StatusDescription = (!Account.IsValidUsername(regModel.Username) ? "Invalid Username (Must be at least 4 characters long.)" : "Invalid Email"); response.OutputStream.Close(); break; } // 5. Is the email already used? if (client.EmailExists(regModel.Email)) { response.StatusCode = 409; //Conflict response.StatusDescription = "Email already exists."; response.OutputStream.Close(); break; } // Add it to the database, and we're good to go! var account = client.AccountCreate(regModel.Username, regModel.PasswordHash, Guid.NewGuid().ToString(), DateTime.Now, DateTime.Now, 0, regModel.Email); // 6. Oh uh? Some error happened! if (account == null) { response.StatusCode = 500; //Internal Server Error response.StatusDescription = "Account Creation Failed."; response.OutputStream.Close(); break; } // Done! response.StatusCode = 201; //Created response.OutputStream.Close(); break; // Account login request case "POST": // 1. Is the request good? if (!request.HasEntityBody) { response.StatusCode = 400; //BadRequest response.OutputStream.Close(); break; } //Are we doing a recovery request? if (request.Url.AbsolutePath.Contains("recover")) { byte[] RequestResponseData; string emailResponse; string resetData = new StreamReader(request.InputStream).ReadToEnd(); var resetModel = JsonConvert.DeserializeObject <Account.RecoverRequestModel>(resetData); // 2. Is the data valid? if (!resetModel.IsRequestValid()) { response.StatusCode = 400; //BadRequest response.StatusDescription = (resetModel.Reset ? "Username " : "Email ") + "cannot be blank."; response.OutputStream.Close(); break; } //Username Recovery if (!resetModel.Reset) { // 3a. Are the credentials good? if (resetModel.Email != null && !client.EmailExists(resetModel.Email)) { response.StatusCode = 404; //Not Found response.StatusDescription = "Email doesn't exist."; response.OutputStream.Close(); break; } // 3b. Are the credentials good? if (!Account.IsValidEmail(resetModel.Email)) { response.StatusCode = 400; //Bad Request response.StatusDescription = "Incorrect email format. Ex: [email protected]"; response.OutputStream.Close(); break; } // 4a. Was it successful? string username; if (!client.AccountRecover(resetModel.Email, out username)) { response.StatusCode = 500; //Internal Server Error response.StatusDescription = "Server Error: Couldn't retrieve your account info."; response.OutputStream.Close(); break; } //Try sending an account recovery mail //4b. Was it successful? if (!client.AccountSendMail(resetModel.Email, username, null)) { response.StatusCode = 500; //Internal Server Error response.StatusDescription = "Server Error: Failed to send recovery info."; response.OutputStream.Close(); break; } // Done! RequestResponseData = Encoding.UTF8.GetBytes(resetModel.Email); response.StatusCode = 200; //OK response.ContentLength64 = RequestResponseData.Length; response.OutputStream.Write(RequestResponseData, 0, RequestResponseData.Length); response.OutputStream.Close(); break; } //Password Reset. //Try generating a reset token else { // 3. Are the credentials good? if (resetModel.Username != null && !client.UsernameExists(resetModel.Username)) { response.StatusCode = 404; //Not Found response.StatusDescription = "Username doesn't exist."; response.OutputStream.Close(); break; } // 4a. Was it successful? string[] parameters; //Email = 0, Token = 1 if (!client.AccountReset(resetModel.Username, out parameters)) { response.StatusCode = 500; //Internal Server Error response.StatusDescription = "Server error: Reset creation failed."; response.OutputStream.Close(); break; } //Try sending a password reset link // 4b. Was it successful? if (!client.AccountSendMail(parameters[0], resetModel.Username, parameters[1])) { response.StatusCode = 500; //Internal Server Error response.StatusDescription = "Server Error: Failed to send reset link."; response.OutputStream.Close(); break; } emailResponse = client.EncodeEmail(parameters[0]); } // Done! RequestResponseData = Encoding.UTF8.GetBytes(emailResponse); response.StatusCode = 200; //OK response.ContentLength64 = RequestResponseData.Length; response.OutputStream.Write(RequestResponseData, 0, RequestResponseData.Length); response.OutputStream.Close(); break; } //Are we resetting a password? if (request.Url.AbsolutePath.Contains("reset-password")) { string resetData = new StreamReader(request.InputStream).ReadToEnd(); var resetModel = JsonConvert.DeserializeObject <Account.ResetRequestModel>(resetData); response.AppendHeader("Access-Control-Allow-Origin", "*"); response.AppendHeader("Access-Control-Allow-Methods", "POST, GET"); //1. Is the data valid? if (!resetModel.IsRequestValid()) { response.StatusCode = 400; //Bad Request byte[] ResetResponseData = Encoding.UTF8.GetBytes("false"); response.ContentLength64 = ResetResponseData.Length; response.OutputStream.Write(ResetResponseData, 0, ResetResponseData.Length); response.OutputStream.Close(); } //2. Does the token exist? resetModel.Token = HttpUtility.UrlDecode(resetModel.Token); if (!client.IsTokenValid(resetModel.Token)) { responseString = Encoding.UTF8.GetBytes("false"); response.StatusCode = 404; //Not Found response.ContentLength64 = responseString.Length; response.OutputStream.Write(responseString, 0, responseString.Length); response.OutputStream.Close(); break; } //3. Was the reset successful? if (!client.AccountPasswordUpdate(resetModel.Token, resetModel.Password)) { responseString = Encoding.UTF8.GetBytes("false"); response.StatusCode = 500; //Internal Server Error response.ContentLength64 = responseString.Length; response.OutputStream.Write(responseString, 0, responseString.Length); response.OutputStream.Close(); break; } responseString = Encoding.UTF8.GetBytes("true"); response.StatusCode = 200; //Ok response.ContentLength64 = responseString.Length; response.OutputStream.Write(responseString, 0, responseString.Length); response.OutputStream.Close(); break; } //Infantry Login string loginData = new StreamReader(request.InputStream).ReadToEnd(); var loginModel = JsonConvert.DeserializeObject <Account.LoginRequestModel>(loginData); // 2. Is the data valid? if (!loginModel.IsRequestValid()) { response.StatusCode = 400; //BadRequest response.OutputStream.Close(); break; } // 3a. Are the credentials good? if (!client.UsernameExists(loginModel.Username)) { response.StatusCode = 404; //Not Found response.StatusDescription = "Username doesn't exist."; response.OutputStream.Close(); break; } // 3b. Are the credentials good? if (!client.IsAccountValid(loginModel.Username, loginModel.PasswordHash)) { response.StatusCode = 404; //Not Found response.StatusDescription = "Incorrect Password."; response.OutputStream.Close(); break; } // Try logging in Account a = client.AccountLogin(loginModel.Username, loginModel.PasswordHash, request.RemoteEndPoint.Address.ToString()); // 4. Was it successful? if (a == null) { response.StatusCode = 400; //BadRequest response.StatusDescription = "Account doesn't exist."; response.OutputStream.Close(); break; } var loginResponseModel = new Account.LoginResponseModel(); loginResponseModel.Username = a.Username; loginResponseModel.Email = a.Email; loginResponseModel.TicketId = a.SessionId; loginResponseModel.DateCreated = a.DateCreated; loginResponseModel.LastAccessed = a.LastAccessed; loginResponseModel.Permission = a.Permission; var loginResponseString = JsonConvert.SerializeObject(loginResponseModel); byte[] loginResponseData = Encoding.UTF8.GetBytes(loginResponseString); response.StatusCode = 200; //OK response.ContentLength64 = loginResponseData.Length; response.OutputStream.Write(loginResponseData, 0, loginResponseData.Length); response.OutputStream.Close(); break; } } catch (Exception e) { if (e.Message.Contains("SQL")) { Console.WriteLine("Unhandled SQL exception"); } } }