email and password change panels added

This commit is contained in:
2024-11-06 14:56:02 +01:00
Unverified
parent 4cbc44f9be
commit 2a0d130914
23 changed files with 441 additions and 66 deletions

View File

@@ -114,6 +114,20 @@ public class AccountsController(IAccountsControllerService accountsControllerSer
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult> PatchAccountUsername([FromBody]AccountUsernameRequest data) => await accountsControllerService.PatchAccountUsername(data);
[HttpPatch("email")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult> PatchAccountEmail([FromBody]AccountEmailRequest data) => await accountsControllerService.PatchAccountEmail(data);
[HttpPatch("password")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult> PatchAccountPassword([FromBody]AccountPasswordRequest data) => await accountsControllerService.PatchAccountPassword(data);
#endregion
[HttpGet("{id}/movies")]

View File

@@ -37,18 +37,13 @@ public class AccountsControllerService(
public async Task<RequestResult> Register(RegisterRequest data)
{
string leftSalt = StringExtensions.CreateRandom(20);
string rightSalt = StringExtensions.CreateRandom(20);
byte[] hash = ComputeHash(data.Password, leftSalt, rightSalt);
Account account = new Account
{
Username = data.Username,
Email = data.Email,
Password = hash,
LeftSalt = leftSalt,
RightSalt = rightSalt,
};
SetPassword(account, data.Password);
await database.Accounts.AddAsync(account);
await database.SaveChangesAsync();
@@ -283,6 +278,36 @@ public class AccountsControllerService(
return RequestResult.Ok();
}
public async Task<RequestResult> PatchAccountEmail(AccountEmailRequest data)
{
Account account = await database.Accounts.FirstAsync(x => x.Id == userService.GetUserId());
if (!ComputeHash(data.Password, account.LeftSalt, account.RightSalt).SequenceEqual(account.Password))
{
return RequestResult.Unauthorized();
}
data.UpdateAccount(account);
await database.SaveChangesAsync();
return RequestResult.Ok();
}
public async Task<RequestResult> PatchAccountPassword(AccountPasswordRequest data)
{
Account account = await database.Accounts.FirstAsync(x => x.Id == userService.GetUserId());
if (!ComputeHash(data.OldPassword, account.LeftSalt, account.RightSalt).SequenceEqual(account.Password))
{
return RequestResult.Unauthorized();
}
SetPassword(account, data.NewPassword);
await database.SaveChangesAsync();
return RequestResult.Ok();
}
#endregion
@@ -338,5 +363,16 @@ public class AccountsControllerService(
protected byte[] ComputeHash(string password, string leftSalt, string rightSalt) => SHA512.HashData(Encoding.UTF8.GetBytes($"{leftSalt}{password}{rightSalt}"));
private void SetPassword(Account account, string password)
{
string leftSalt = StringExtensions.CreateRandom(20);
string rightSalt = StringExtensions.CreateRandom(20);
byte[] hash = ComputeHash(password, leftSalt, rightSalt);
account.Password = hash;
account.LeftSalt = leftSalt;
account.RightSalt = rightSalt;
}
#endregion
}

View File

@@ -22,6 +22,8 @@ public interface IAccountsControllerService
Task<RequestResult> GetAccountInfo(long id);
Task<RequestResult> PutAccountProfileInfo(AccountProfileInfoRequest data);
Task<RequestResult> PatchAccountUsername(AccountUsernameRequest data);
Task<RequestResult> PatchAccountEmail(AccountEmailRequest data);
Task<RequestResult> PatchAccountPassword(AccountPasswordRequest data);
Task<RequestResult> GetAccountRatedMovies(long id, MovieRatedQueryParameters query);
Task<RequestResult> GetAccountRatedSeries(long id, SeriesRatedQueryParameters query);
Task<RequestResult> GetAccountRatedPersons(long id, PersonRatedQueryParameters query);

View File

@@ -0,0 +1,15 @@
using FluentValidation;
using WatchIt.Common.Model.Accounts;
using WatchIt.Database;
namespace WatchIt.WebAPI.Validators.Accounts;
public class AccountEmailRequestValidator : AbstractValidator<AccountEmailRequest>
{
public AccountEmailRequestValidator(DatabaseContext database)
{
RuleFor(x => x.NewEmail).EmailAddress()
.CannotBeIn(database.Accounts, x => x.Email)
.WithMessage("Email was already used");
}
}

View File

@@ -0,0 +1,17 @@
using FluentValidation;
using WatchIt.Common.Model.Accounts;
using WatchIt.Database;
namespace WatchIt.WebAPI.Validators.Accounts;
public class AccountPasswordRequestValidator : AbstractValidator<AccountPasswordRequest>
{
public AccountPasswordRequestValidator(DatabaseContext database)
{
RuleFor(x => x.NewPassword).MinimumLength(8)
.Must(x => x.Any(char.IsUpper)).WithMessage("Password must contain at least one uppercase letter.")
.Must(x => x.Any(char.IsLower)).WithMessage("Password must contain at least one lowercase letter.")
.Must(x => x.Any(char.IsDigit)).WithMessage("Password must contain at least one digit.")
.Equal(x => x.NewPasswordConfirmation);
}
}