From 6648b79e1b2f92449d5816d0722b7a3d72f259d5 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Fri, 13 Jan 2023 09:01:44 -0600 Subject: [PATCH] Email change now requires a password --- API/Controllers/AccountController.cs | 10 +++++++++- API/DTOs/Account/UpdateEmailDto.cs | 1 + API/Services/Tasks/StatsService.cs | 1 + UI/Web/src/app/_services/account.service.ts | 4 ++-- .../change-email/change-email.component.html | 11 +++++++++++ .../change-email/change-email.component.ts | 3 ++- openapi.json | 6 +++++- 7 files changed, 31 insertions(+), 5 deletions(-) diff --git a/API/Controllers/AccountController.cs b/API/Controllers/AccountController.cs index 1592a13d7..2eef78157 100644 --- a/API/Controllers/AccountController.cs +++ b/API/Controllers/AccountController.cs @@ -289,7 +289,15 @@ public async Task UpdateEmail(UpdateEmailDto dto) var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); if (user == null) return Unauthorized("You do not have permission"); - if (dto == null || string.IsNullOrEmpty(dto.Email)) return BadRequest("Invalid payload"); + if (dto == null || string.IsNullOrEmpty(dto.Email) || string.IsNullOrEmpty(dto.Password)) return BadRequest("Invalid payload"); + + + // Validate this user's password + if (! await _userManager.CheckPasswordAsync(user, dto.Password)) + { + _logger.LogCritical("A user tried to change {UserName}'s email, but password didn't validate", user.UserName); + return BadRequest("You do not have permission"); + } // Validate no other users exist with this email if (user.Email.Equals(dto.Email)) return Ok("Nothing to do"); diff --git a/API/DTOs/Account/UpdateEmailDto.cs b/API/DTOs/Account/UpdateEmailDto.cs index 9b92095d8..2363790f6 100644 --- a/API/DTOs/Account/UpdateEmailDto.cs +++ b/API/DTOs/Account/UpdateEmailDto.cs @@ -3,4 +3,5 @@ public class UpdateEmailDto { public string Email { get; set; } + public string Password { get; set; } } diff --git a/API/Services/Tasks/StatsService.cs b/API/Services/Tasks/StatsService.cs index b76903c45..a4cb355c5 100644 --- a/API/Services/Tasks/StatsService.cs +++ b/API/Services/Tasks/StatsService.cs @@ -207,6 +207,7 @@ public async Task SendCancellation() private async Task GetPercentageOfLibrariesWithFolderWatchingEnabled() { var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).ToList(); + if (libraries.Count == 0) return 0.0f; return libraries.Count(l => l.FolderWatching) / (1.0f * libraries.Count); } diff --git a/UI/Web/src/app/_services/account.service.ts b/UI/Web/src/app/_services/account.service.ts index 299925020..ee1dd2461 100644 --- a/UI/Web/src/app/_services/account.service.ts +++ b/UI/Web/src/app/_services/account.service.ts @@ -204,8 +204,8 @@ export class AccountService implements OnDestroy { return this.httpClient.post(this.baseUrl + 'account/update', model); } - updateEmail(email: string) { - return this.httpClient.post(this.baseUrl + 'account/update/email', {email}); + updateEmail(email: string, password: string) { + return this.httpClient.post(this.baseUrl + 'account/update/email', {email, password}); } updateAgeRestriction(ageRating: AgeRating, includeUnknowns: boolean) { diff --git a/UI/Web/src/app/user-settings/change-email/change-email.component.html b/UI/Web/src/app/user-settings/change-email/change-email.component.html index 7632cec00..ec859cfbb 100644 --- a/UI/Web/src/app/user-settings/change-email/change-email.component.html +++ b/UI/Web/src/app/user-settings/change-email/change-email.component.html @@ -39,6 +39,17 @@

Email +
+ + +
+
+ This field is required +
+
+
+
diff --git a/UI/Web/src/app/user-settings/change-email/change-email.component.ts b/UI/Web/src/app/user-settings/change-email/change-email.component.ts index 6455fd9b8..2864baf43 100644 --- a/UI/Web/src/app/user-settings/change-email/change-email.component.ts +++ b/UI/Web/src/app/user-settings/change-email/change-email.component.ts @@ -34,6 +34,7 @@ export class ChangeEmailComponent implements OnInit, OnDestroy { this.accountService.currentUser$.pipe(takeUntil(this.onDestroy), shareReplay(), take(1)).subscribe(user => { this.user = user; this.form.addControl('email', new FormControl(user?.email, [Validators.required, Validators.email])); + this.form.addControl('password', new FormControl('', [Validators.required])); this.cdRef.markForCheck(); this.accountService.isEmailConfirmed().subscribe((confirmed) => { this.emailConfirmed = confirmed; @@ -60,7 +61,7 @@ export class ChangeEmailComponent implements OnInit, OnDestroy { const model = this.form.value; this.errors = []; - this.accountService.updateEmail(model.email).subscribe((updateEmailResponse: UpdateEmailResponse) => { + this.accountService.updateEmail(model.email, model.password).subscribe((updateEmailResponse: UpdateEmailResponse) => { if (updateEmailResponse.emailSent) { if (updateEmailResponse.hadNoExistingEmail) { this.toastr.success('An email has been sent to ' + model.email + ' for confirmation.'); diff --git a/openapi.json b/openapi.json index 6327af78c..807e7fad2 100644 --- a/openapi.json +++ b/openapi.json @@ -7,7 +7,7 @@ "name": "GPL-3.0", "url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE" }, - "version": "0.6.1.27" + "version": "0.6.1.28" }, "servers": [ { @@ -13690,6 +13690,10 @@ "email": { "type": "string", "nullable": true + }, + "password": { + "type": "string", + "nullable": true } }, "additionalProperties": false