Skip to content

Commit

Permalink
Email change now requires a password
Browse files Browse the repository at this point in the history
  • Loading branch information
majora2007 committed Jan 13, 2023
1 parent 80c7d2c commit 6648b79
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 5 deletions.
10 changes: 9 additions & 1 deletion API/Controllers/AccountController.cs
Expand Up @@ -289,7 +289,15 @@ public async Task<ActionResult> 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");
Expand Down
1 change: 1 addition & 0 deletions API/DTOs/Account/UpdateEmailDto.cs
Expand Up @@ -3,4 +3,5 @@
public class UpdateEmailDto
{
public string Email { get; set; }
public string Password { get; set; }
}
1 change: 1 addition & 0 deletions API/Services/Tasks/StatsService.cs
Expand Up @@ -207,6 +207,7 @@ public async Task SendCancellation()
private async Task<float> 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);
}

Expand Down
4 changes: 2 additions & 2 deletions UI/Web/src/app/_services/account.service.ts
Expand Up @@ -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<UpdateEmailResponse>(this.baseUrl + 'account/update/email', {email});
updateEmail(email: string, password: string) {
return this.httpClient.post<UpdateEmailResponse>(this.baseUrl + 'account/update/email', {email, password});
}

updateAgeRestriction(ageRating: AgeRating, includeUnknowns: boolean) {
Expand Down
Expand Up @@ -39,6 +39,17 @@ <h4 id="email-card">Email
</div>
</div>

<div class="mb-3">
<label for="password" class="form-label">Current Password</label>
<input class="form-control custom-input" type="password" id="password" formControlName="password"
[class.is-invalid]="form.get('password')?.invalid && form.get('password')?.touched">
<div id="password-validations" class="invalid-feedback" *ngIf="form.dirty || form.touched">
<div *ngIf="form.get('password')?.errors?.required">
This field is required
</div>
</div>
</div>

<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end mb-3">
<button type="button" class="flex-fill btn btn-secondary me-2" aria-describedby="email-card" (click)="resetForm()">Reset</button>
<button type="submit" class="flex-fill btn btn-primary" aria-describedby="email-card" (click)="saveForm()" [disabled]="!form.valid || !(form.dirty || form.touched)">Save</button>
Expand Down
Expand Up @@ -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;
Expand All @@ -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.');
Expand Down
6 changes: 5 additions & 1 deletion openapi.json
Expand Up @@ -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": [
{
Expand Down Expand Up @@ -13690,6 +13690,10 @@
"email": {
"type": "string",
"nullable": true
},
"password": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
Expand Down

0 comments on commit 6648b79

Please sign in to comment.