Skip to content

Commit 4b4c519

Browse files
committed
Limit updating the user email address to three times per hour.
1 parent de27bf7 commit 4b4c519

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

Source/Api/Controllers/UserController.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,22 @@
1313
using Exceptionless.Core.Mail;
1414
using Exceptionless.Core.Repositories;
1515
using Exceptionless.Core.Models;
16+
using Exceptionless.DateTimeExtensions;
1617
using FluentValidation;
18+
using Foundatio.Caching;
1719
using Foundatio.Logging;
1820

1921
namespace Exceptionless.Api.Controllers {
2022
[RoutePrefix(API_PREFIX + "/users")]
2123
[Authorize(Roles = AuthorizationRoles.User)]
2224
public class UserController : RepositoryApiController<IUserRepository, User, ViewUser, User, UpdateUser> {
2325
private readonly IOrganizationRepository _organizationRepository;
26+
private readonly ICacheClient _cacheClient;
2427
private readonly IMailer _mailer;
2528

26-
public UserController(IUserRepository userRepository, IOrganizationRepository organizationRepository, IMailer mailer) : base(userRepository) {
29+
public UserController(IUserRepository userRepository, IOrganizationRepository organizationRepository, ICacheClient cacheClient, IMailer mailer) : base(userRepository) {
2730
_organizationRepository = organizationRepository;
31+
_cacheClient = new ScopedCacheClient(cacheClient, "user");
2832
_mailer = mailer;
2933
}
3034

@@ -117,12 +121,18 @@ public async Task<IHttpActionResult> UpdateEmailAddressAsync(string id, string e
117121
return NotFound();
118122

119123
email = email.ToLower();
120-
if (!await IsEmailAddressAvailableInternalAsync(email))
121-
return BadRequest("A user with this email address already exists.");
122-
123124
if (String.Equals(ExceptionlessUser.EmailAddress, email, StringComparison.OrdinalIgnoreCase))
124125
return Ok(new UpdateEmailAddressResult { IsVerified = user.IsEmailAddressVerified });
125126

127+
// Only allow 3 email address updates per hour period by a single user.
128+
string updateEmailAddressAttemptsCacheKey = $"{ExceptionlessUser.Id}:attempts";
129+
long attempts = await _cacheClient.IncrementAsync(updateEmailAddressAttemptsCacheKey, 1, DateTime.UtcNow.Ceiling(TimeSpan.FromHours(1)));
130+
if (attempts > 3)
131+
return BadRequest("Update email address rate limit reached. Please try updating later.");
132+
133+
if (!await IsEmailAddressAvailableInternalAsync(email))
134+
return BadRequest("A user with this email address already exists.");
135+
126136
user.ResetPasswordResetToken();
127137
user.EmailAddress = email;
128138
user.IsEmailAddressVerified = user.OAuthAccounts.Count(oa => String.Equals(oa.EmailAddress(), email, StringComparison.OrdinalIgnoreCase)) > 0;

0 commit comments

Comments
 (0)