Update from Json to www-formdata

This commit is contained in:
2025-06-20 17:43:13 -07:00
parent 91e58fa267
commit c4ad0f2c10
2 changed files with 285 additions and 298 deletions
+7
View File
@@ -29,3 +29,10 @@ Program
DTO
Cannot send dotnet List -> must be arrays
Need to update local server to use www-formdata instead of json
PaymentController
PaymentResponse is still tied to Stripe.
Need to change to Interface so different services can be interchanged
ProductController
Need to figure out new way to download purchased items as there is currently no way
@@ -1,10 +1,10 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using MistoxWebsite.Shared;
using System.Security.Claims;
using MistoxWebsite.Server.Services;
using MistoxWebsite.Server.Services.DatabaseService;
using Microsoft.AspNetCore.Authentication.Cookies;
using MistoxWebsite.Server.Entities;
namespace MistoxWebsite.Server.Controllers {
[ApiController]
@@ -13,28 +13,26 @@ namespace MistoxWebsite.Server.Controllers {
DatabaseService _accountContext;
EmailService _emailContext;
public AuthenticationController( DatabaseService DatabaseContext, EmailService emailContext ) {
public AuthenticationController(DatabaseService DatabaseContext, EmailService emailContext) {
_accountContext = DatabaseContext;
_emailContext = emailContext;
}
// In Account -> References UserName / PasswordHash
// Out Account
[Route( "api/account/login" )]
[Route("api/account/login")]
[HttpPost]
public async Task<ActionResult<Account>> Login( [FromBody] Account request ) {
public async Task<ActionResult<Account>> Login([FromForm] string UserName, [FromForm] string PasswordHash, [FromForm] bool StayLoggedIn) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( test.EmailVerified == true ) {
if( test.SiteData.FailedPasswordLock ) {
if( test.SiteData.CurrentPasswordAttempts >= test.SiteData.PasswordAttempts ) {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
if (test.EmailVerified == true) {
if (test.SiteData.FailedPasswordLock) {
if (test.SiteData.CurrentPasswordAttempts >= test.SiteData.PasswordAttempts) {
return new Account() { Error = "Too many failed password attempts. Please reset your password" };
}
}
if( BCrypt.Net.BCrypt.Verify( request.PasswordHash, test.PasswordHash ) ) {
if (BCrypt.Net.BCrypt.Verify(PasswordHash, test.PasswordHash)) {
test.SiteData.CurrentPasswordAttempts = 0;
await _accountContext.SetAccount( test );
await _accountContext.SetAccount(test);
AccountClaims aClaims = await getClaims(test.ID);
List<Claim> claims = new List<Claim>() {
@@ -48,64 +46,306 @@ namespace MistoxWebsite.Server.Controllers {
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal( new ClaimsIdentity( claims, "Auth" ) ),
new ClaimsPrincipal(new ClaimsIdentity(claims, "Auth")),
new AuthenticationProperties {
ExpiresUtc = DateTime.UtcNow.AddYears(30), // Add 30 years with sliding on
IsPersistent = request.EmailVerified, // Is set from the StayLoggedIn
IsPersistent = StayLoggedIn, // Is set from the StayLoggedIn
}
);
return test;
} else {
}
else {
test.SiteData.CurrentPasswordAttempts += 1;
await _accountContext.SetAccount( test );
await _accountContext.SetAccount(test);
return new Account() { Error = "Wrong password" };
}
}else{
await SendVerify(test);
}
else {
await SendVerify(test.UserName);
return new Account() { Error = "A new verify email has been sent. \n Note only 1 email send every 5 mintes" };
}
}
return new Account() { Error = "User doesn't exist" };
} catch( Exception ex ) {
} catch (Exception ex) {
return new Account() { Error = ex.Message };
}
}
// In Account -> References UserName / PasswordHash
// Out Account
[Route( "api/account/session" )]
[Route("api/account/session")]
[HttpPost]
public async Task<ActionResult<Account>> LoginSession( [FromBody] Account request ) {
public async Task<ActionResult<Account>> LoginSession([FromBody] Account request) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( request.PasswordHash == test.PasswordHash ) {
if (test != null) {
if (request.PasswordHash == test.PasswordHash) {
return test;
} else {
}
else {
test.SiteData.CurrentPasswordAttempts += 1;
await _accountContext.SetAccount( test );
await _accountContext.SetAccount(test);
return new Account() { Error = "Wrong password" };
}
}
return new Account() { Error = "User doesn't exist" };
} catch( Exception ex ) {
} catch (Exception ex) {
return new Account() { Error = ex.Message };
}
}
// In Account
// Out List<String>
[Route( "api/account/claims" )]
[Route("api/account/claims")]
[HttpPost]
public async Task<ActionResult<AccountClaims>> Claims( [FromBody] Account Account ) {
public async Task<ActionResult<AccountClaims>> Claims([FromBody] Account Account) {
AccountClaims claims = await getClaims(Account.ID);
return claims;
}
async Task<AccountClaims> getClaims( int AccountID ) {
[Route("api/account/register")]
[HttpPost]
public async Task<ActionResult<Account>> Register([FromForm] string Email, [FromForm] string UserName, [FromForm] string PasswordHash) {
try {
if (await _accountContext.GetAccount(UserName.ToLower()) == null) {
if (await _accountContext.GetAccount(Email.ToLower()) == null) {
Account? created = new Account() {
UserName = UserName.ToLower(),
Email = Email.ToLower(),
EmailVerified = false,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(PasswordHash),
};
await _accountContext.NewAccount(created);
created = await _accountContext.GetAccount(Email.ToLower());
if (created != null) {
AccountClaims aClaims = await getClaims(created.ID);
List<Claim> claims = new List<Claim>() {
new Claim(ClaimTypes.Name, aClaims.UserName),
new Claim(ClaimTypes.Email, aClaims.Email),
new Claim("emailverified", aClaims.EmailVerified),
new Claim(ClaimTypes.Role, aClaims.Role),
new Claim("LockAccount", aClaims.FailedPasswordLock)
};
await SendVerify(created.UserName);
return created;
}
return new Account() { Error = "Unknown Error" };
}
else {
return new Account() { Error = "Email is already in use" };
}
}
else {
return new Account() { Error = "UserName is taken" };
}
} catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return new Account() { Error = ex.Message };
}
}
[Route("api/account/changepassword")]
[HttpPost]
public async Task<ActionResult<bool>> ChangePassword([FromForm]string UserName, [FromForm]string OldPassword, [FromForm]string NewPassword) {
try {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
if (BCrypt.Net.BCrypt.Verify(OldPassword, test.PasswordHash)) {
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword);
test.SiteData.CurrentPasswordAttempts = 0;
await _accountContext.SetAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("api/account/toggleAccountLock")]
[HttpPost]
public async Task<ActionResult<string>> ToggleAccountLock([FromForm]string UserName, [FromForm]bool AccountLock) {
try {
Account? test = await _accountContext.GetAccount(UserName);
if (test != null) {
test.SiteData.FailedPasswordLock = AccountLock;
test.SiteData.CurrentPasswordAttempts = 0;
await _accountContext.SetAccount(test);
return "Account Lock Status Updated";
}
return "Unknown Error Occurred";
} catch (Exception ex) {
return ex.Message;
}
}
[Route("api/account/get")]
[HttpPost]
public async Task<ActionResult<Account?>> Get() {
try {
if (User.Identity != null && User.Identity.IsAuthenticated) {
string? email = User.FindFirstValue(ClaimTypes.Email);
if (!string.IsNullOrEmpty(email)) {
Account? test = await _accountContext.GetAccount(email);
if (test != null) {
return test;
}
}
}
return Ok();
} catch {
return Ok();
}
}
[Route("api/account/logout")]
[HttpPost]
public async Task Logout() {
await HttpContext.SignOutAsync();
}
[Route("api/account/sendverifyemail")]
[HttpPost]
public async Task<ActionResult<string>> SendVerify([FromForm]string UserName) {
try {
string key = "v" + UserName;
// Stop from sending multiple emails quickly
if (_emailContext._SentEmails.ContainsKey(key)) {
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now) {
return "Cannot sent another verify email until 5 minutes has elapsed ";
}
else {
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
test.SiteData.EmailToken = Guid.NewGuid().ToString();
await _accountContext.SetAccount(test);
string EmailContents = EmailService.VerifyEmailEmail;
EmailContents = Substitue(EmailContents, "@UserName", UserName);
EmailContents = Substitue(EmailContents, "@UserName", UserName);
EmailContents = Substitue(EmailContents, "@VerifyPassword", test.SiteData.EmailToken);
string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents);
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account not found";
} catch (Exception) {
return "The connection couldn't be established to the email server";
}
}
[Route("api/account/verifyemail")]
[HttpPost]
public async Task<ActionResult<bool>> VerifyEmail([FromForm]string UserName, [FromForm]string EmailToken) {
try {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
if (test.SiteData.EmailToken == EmailToken) {
test.SiteData.EmailToken = "";
test.EmailVerified = true;
await _accountContext.SetAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("api/account/sendresetpassword")]
[HttpPost]
public async Task<ActionResult<string>> ResetPassword([FromForm] string Email) {
try {
string key = "p" + Email.ToLower();
// Stop from sending multiple emails quickly
if (_emailContext._SentEmails.ContainsKey(key)) {
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now) {
return "Cannot sent another reset requests until 5 minutes has elapsed";
}
else {
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _accountContext.GetAccount(Email.ToLower());
if (test != null) {
test.SiteData.EmailToken = Guid.NewGuid().ToString();
await _accountContext.SetAccount(test);
string EmailContents = EmailService.ResetPasswordEmail;
EmailContents = Substitue(EmailContents, "@UserName", test.UserName);
EmailContents = Substitue(EmailContents, "@UserName", test.UserName);
EmailContents = Substitue(EmailContents, "@ResetPassWord", test.SiteData.EmailToken);
string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents);
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account Not Found";
} catch (Exception) {
return "The connection couldn't be established to the email server";
}
}
[Route("api/account/resetpassword")]
[HttpPost]
public async Task<ActionResult<bool>> ResetPwdVerify([FromForm] string UserName, [FromForm] string NewPassword, [FromForm] string ResetToken) {
try {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null && !string.IsNullOrEmpty(test.SiteData.EmailToken)) {
if (test.SiteData.EmailToken == ResetToken) {
test.SiteData.CurrentPasswordAttempts = 0;
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword);
await _accountContext.SetAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("api/account/delete")]
[HttpPost]
public async Task<ActionResult<bool>> delete([FromForm]string UserName, [FromForm]string Password) {
try {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
if (BCrypt.Net.BCrypt.Verify(Password, test.PasswordHash)) {
await _accountContext.DeleteAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
// Helper Functions
string Substitue(string message, string subString, string Replacement) {
for (int i = 0; i < (message.Length - subString.Length); i++) {
if (message.Substring(i, subString.Length) == subString) {
string before = message.Substring(0, i);
string after = message.Substring(i + subString.Length);
return before + Replacement + after;
}
}
return message;
}
async Task<AccountClaims> getClaims(int AccountID) {
try {
Account? test = await _accountContext.GetAccountByID(AccountID);
if( test != null ) {
if (test != null) {
AccountClaims aClaims = new AccountClaims() {
UserName = test.UserName,
Email = test.Email,
@@ -121,265 +361,5 @@ namespace MistoxWebsite.Server.Controllers {
}
}
// In Account -> Full account
// Out Account
[Route( "api/account/register" )]
[HttpPost]
public async Task<ActionResult<Account>> Register( [FromBody] Account request ) {
try {
if( await _accountContext.GetAccount( request.UserName.ToLower() ) == null ) {
if( await _accountContext.GetAccount( request.Email.ToLower() ) == null ) {
Account? created = new Account(){
UserName = request.UserName.ToLower(),
Email = request.Email.ToLower(),
EmailVerified = false,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.PasswordHash),
};
await _accountContext.NewAccount( created );
created = await _accountContext.GetAccount( request.Email.ToLower() );
if( created != null ) {
AccountClaims aClaims = await getClaims(created.ID);
List<Claim> claims = new List<Claim>() {
new Claim(ClaimTypes.Name, aClaims.UserName),
new Claim(ClaimTypes.Email, aClaims.Email),
new Claim("emailverified", aClaims.EmailVerified),
new Claim(ClaimTypes.Role, aClaims.Role),
new Claim("LockAccount", aClaims.FailedPasswordLock)
};
await SendVerify(created);
return created;
}
return new Account() { Error = "Unknown Error" };
} else {
return new Account() { Error = "Email is already in use" };
}
} else {
return new Account() { Error = "UserName is taken" };
}
} catch( Exception ex ) {
Console.WriteLine("Error: " + ex.Message);
return new Account() { Error = ex.Message };
}
}
// In Account -> References UserName / PasswordHash( Current Password ) / Error( New Password )
// Out Bool
[Route( "api/account/changepassword" )]
[HttpPost]
public async Task<ActionResult<bool>> ChangePassword( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( BCrypt.Net.BCrypt.Verify( request.PasswordHash, test.PasswordHash ) ) {
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword( request.Error );
test.SiteData.CurrentPasswordAttempts = 0;
await _accountContext.SetAccount( test );
return true;
}
}
return false;
} catch {
return false;
}
}
// In Account -> References UserName / SiteData FailedPasswordLock / SiteData.PasswordAttempts
// Out Error String
[Route( "api/account/toggleAccountLock" )]
[HttpPost]
public async Task<ActionResult<string>> ToggleAccountLock( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName);
if( test != null ) {
test.SiteData.FailedPasswordLock = request.SiteData.FailedPasswordLock;
test.SiteData.CurrentPasswordAttempts = 0;
test.SiteData.PasswordAttempts = request.SiteData.PasswordAttempts;
await _accountContext.SetAccount( test );
return "Account Lock Status Updated";
}
return "Unknown Error Occurred";
} catch( Exception ex ) {
return ex.Message;
}
}
// Out Account -> only if logged in
[Route( "api/account/get" )]
[HttpPost]
public async Task<ActionResult<Account?>> Get() {
try {
if( User.Identity != null && User.Identity.IsAuthenticated ) {
string? email = User.FindFirstValue(ClaimTypes.Email);
if( !string.IsNullOrEmpty( email ) ) {
Account? test = await _accountContext.GetAccount(email);
if( test != null ) {
return test;
}
}
}
return Ok();
} catch {
return Ok();
}
}
// In Null
// Out Null
[Route( "api/account/logout" )]
[HttpPost]
public async Task Logout() {
await HttpContext.SignOutAsync();
}
string Substitue( string message, string subString, string Replacement ) {
for( int i = 0; i < (message.Length - subString.Length); i++ ) {
if( message.Substring( i, subString.Length ) == subString ) {
string before = message.Substring( 0, i );
string after = message.Substring(i + subString.Length );
return before + Replacement + after;
}
}
return message;
}
// In Account -> References UserName
// Out Success bool
[Route( "api/account/sendverifyemail" )]
[HttpPost]
public async Task<ActionResult<string>> SendVerify( [FromBody] Account request ) {
try {
string key = "v" + request.UserName;
// Stop from sending multiple emails quickly
if ( _emailContext._SentEmails.ContainsKey(key) ){
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now){
return "Cannot sent another verify email until 5 minutes has elapsed ";
}else{
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
test.SiteData.EmailToken = Guid.NewGuid().ToString();
await _accountContext.SetAccount( test );
string EmailContents = EmailService.VerifyEmailEmail;
EmailContents = Substitue( EmailContents, "@UserName", request.UserName );
EmailContents = Substitue( EmailContents, "@UserName", request.UserName );
EmailContents = Substitue( EmailContents, "@VerifyPassword", test.SiteData.EmailToken );
string result = _emailContext.Send( test.Email, EmailService.VerifyEmailSubject, EmailContents );
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account not found";
} catch (Exception) {
return "The connection couldn't be established to the email server";
}
}
// In Account -> References UserName / Password( EmailToken )
// Out Success bool
[Route( "api/account/verifyemail" )]
[HttpPost]
public async Task<ActionResult<bool>> VerifyEmail( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( test.SiteData.EmailToken == request.PasswordHash ) {
test.SiteData.EmailToken = "";
test.EmailVerified = true;
await _accountContext.SetAccount( test );
return true;
}
}
return false;
} catch {
return false;
}
}
// In Account -> References Email
// Out Success bool
[Route( "api/account/sendresetpassword" )]
[HttpPost]
public async Task<ActionResult<string>> ResetPassword( [FromBody] Account request ) {
try {
string key = "p" + request.Email.ToLower();
// Stop from sending multiple emails quickly
if ( _emailContext._SentEmails.ContainsKey(key) ){
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now){
return "Cannot sent another reset requests until 5 minutes has elapsed";
}else{
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _accountContext.GetAccount(request.Email.ToLower());
if( test != null ) {
test.SiteData.EmailToken = Guid.NewGuid().ToString();
await _accountContext.SetAccount( test );
string EmailContents = EmailService.ResetPasswordEmail;
EmailContents = Substitue( EmailContents, "@UserName", test.UserName );
EmailContents = Substitue( EmailContents, "@UserName", test.UserName );
EmailContents = Substitue( EmailContents, "@ResetPassWord", test.SiteData.EmailToken );
string result = _emailContext.Send( test.Email, EmailService.VerifyEmailSubject, EmailContents );
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account Not Found";
} catch (Exception) {
return "The connection couldn't be established to the email server";
}
}
// In Account -> References UserName / Password( NewPassword ) / Error( EmailToken )
// Out Success bool
[Route( "api/account/resetpassword" )]
[HttpPost]
public async Task<ActionResult<bool>> ResetPwdVerify( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null && !string.IsNullOrEmpty(test.SiteData.EmailToken) ) {
if( test.SiteData.EmailToken == request.Error ) {
test.SiteData.CurrentPasswordAttempts = 0;
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword( request.PasswordHash );
await _accountContext.SetAccount( test );
return true;
}
}
return false;
} catch {
return false;
}
}
// In Account -> References UserName / Password( Password ) )
// Out Success bool
[Route( "api/account/delete" )]
[HttpPost]
public async Task<ActionResult<bool>> delete( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( BCrypt.Net.BCrypt.Verify( request.PasswordHash, test.PasswordHash ) ) {
await _accountContext.DeleteAccount( test );
return true;
}
}
return false;
} catch {
return false;
}
}
}
}