From 4b4c5193bfb9a44b41f862891a01dd203fe0f7a9 Mon Sep 17 00:00:00 2001 From: Blake Niemyjski Date: Wed, 3 Feb 2016 11:18:13 -0600 Subject: [PATCH] Limit updating the user email address to three times per hour. --- Source/Api/Controllers/UserController.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Source/Api/Controllers/UserController.cs b/Source/Api/Controllers/UserController.cs index fbd700bb90..40feaae661 100644 --- a/Source/Api/Controllers/UserController.cs +++ b/Source/Api/Controllers/UserController.cs @@ -13,7 +13,9 @@ using Exceptionless.Core.Mail; using Exceptionless.Core.Repositories; using Exceptionless.Core.Models; +using Exceptionless.DateTimeExtensions; using FluentValidation; +using Foundatio.Caching; using Foundatio.Logging; namespace Exceptionless.Api.Controllers { @@ -21,10 +23,12 @@ namespace Exceptionless.Api.Controllers { [Authorize(Roles = AuthorizationRoles.User)] public class UserController : RepositoryApiController { private readonly IOrganizationRepository _organizationRepository; + private readonly ICacheClient _cacheClient; private readonly IMailer _mailer; - public UserController(IUserRepository userRepository, IOrganizationRepository organizationRepository, IMailer mailer) : base(userRepository) { + public UserController(IUserRepository userRepository, IOrganizationRepository organizationRepository, ICacheClient cacheClient, IMailer mailer) : base(userRepository) { _organizationRepository = organizationRepository; + _cacheClient = new ScopedCacheClient(cacheClient, "user"); _mailer = mailer; } @@ -117,12 +121,18 @@ public async Task UpdateEmailAddressAsync(string id, string e return NotFound(); email = email.ToLower(); - if (!await IsEmailAddressAvailableInternalAsync(email)) - return BadRequest("A user with this email address already exists."); - if (String.Equals(ExceptionlessUser.EmailAddress, email, StringComparison.OrdinalIgnoreCase)) return Ok(new UpdateEmailAddressResult { IsVerified = user.IsEmailAddressVerified }); + // Only allow 3 email address updates per hour period by a single user. + string updateEmailAddressAttemptsCacheKey = $"{ExceptionlessUser.Id}:attempts"; + long attempts = await _cacheClient.IncrementAsync(updateEmailAddressAttemptsCacheKey, 1, DateTime.UtcNow.Ceiling(TimeSpan.FromHours(1))); + if (attempts > 3) + return BadRequest("Update email address rate limit reached. Please try updating later."); + + if (!await IsEmailAddressAvailableInternalAsync(email)) + return BadRequest("A user with this email address already exists."); + user.ResetPasswordResetToken(); user.EmailAddress = email; user.IsEmailAddressVerified = user.OAuthAccounts.Count(oa => String.Equals(oa.EmailAddress(), email, StringComparison.OrdinalIgnoreCase)) > 0;