public async Task <CheckOneTimeCodeResponse> CheckOneTimeCodeAsync(string sentTo, string shortCode) { var otc = await _oneTimeCodeStore.GetOneTimeCodeAsync(sentTo); if (otc == null) { return(new CheckOneTimeCodeResponse(CheckOneTimeCodeResult.NotFound)); } if (otc.ExpiresUTC < DateTime.UtcNow) { return(new CheckOneTimeCodeResponse(CheckOneTimeCodeResult.Expired)); } if (!string.IsNullOrEmpty(shortCode) && shortCode.Length <= 8) { if (otc.FailedAttemptCount > 1) { // maximum of 2 attempts during code validity period to prevent guessing attacks // long code remains valid, preventing account lockout attacks (and giving a fumbling but valid user another way in) return(new CheckOneTimeCodeResponse(CheckOneTimeCodeResult.ShortCodeLocked)); } var checkResult = _passwordHashService.CheckPasswordHash(otc.ShortCodeHash, shortCode); if (checkResult == CheckPaswordHashResult.Matches || checkResult == CheckPaswordHashResult.MatchesNeedsRehash) { await _oneTimeCodeStore.ExpireOneTimeCodeAsync(sentTo); return(new CheckOneTimeCodeResponse(CheckOneTimeCodeResult.Verified, sentTo, otc.RedirectUrl)); } } await _oneTimeCodeStore.UpdateOneTimeCodeFailureAsync(sentTo, otc.FailedAttemptCount + 1); return(new CheckOneTimeCodeResponse(CheckOneTimeCodeResult.CodeIncorrect)); }
public async Task <Response <CheckOneTimeCodeResult, CheckOneTimeCodeStatus> > CheckOneTimeCodeAsync(string sentTo, string shortCode, string clientNonce) { _logger.LogTrace("Checking short code"); var response = await _oneTimeCodeStore.GetOneTimeCodeAsync(sentTo); if (response.HasError) { return(new Response <CheckOneTimeCodeResult, CheckOneTimeCodeStatus>( CheckOneTimeCodeStatus.Error(_localizer["One time code not found."], CheckOneTimeCodeStatusCode.NotFound))); } var otc = response.Result; if (otc.ExpiresUTC < DateTime.UtcNow) { _logger.LogDebug("The one time code has expired."); return(new Response <CheckOneTimeCodeResult, CheckOneTimeCodeStatus>( CheckOneTimeCodeStatus.Error(_localizer["The one time code has expired."], CheckOneTimeCodeStatusCode.Expired))); } if (!string.IsNullOrEmpty(shortCode) && shortCode.Length == PasswordlessLoginConstants.OneTimeCode.ShortCodeLength) { if (otc.FailedAttemptCount >= PasswordlessLoginConstants.OneTimeCode.MaxFailedAttemptCount) { // maximum of 3 attempts during code validity period to prevent guessing attacks // long code remains valid, preventing account lockout attacks (and giving a fumbling but valid user another way in) _logger.LogDebug("The one time code is locked (too many failed attempts to use it)."); return(new Response <CheckOneTimeCodeResult, CheckOneTimeCodeStatus>( CheckOneTimeCodeStatus.Error(_localizer["The one time code is locked."], CheckOneTimeCodeStatusCode.ShortCodeLocked))); } if (shortCode == otc.ShortCode) { _logger.LogDebug("The one time code matches"); return(await ExpireTokenAndValidateNonceAsync(otc, clientNonce)); } } else { _logger.LogDebug("The one time code was missing or was the wrong length"); } _logger.LogDebug("Updating failure count for one time code"); await _oneTimeCodeStore.UpdateOneTimeCodeFailureAsync(sentTo, otc.FailedAttemptCount + 1); return(new Response <CheckOneTimeCodeResult, CheckOneTimeCodeStatus>( CheckOneTimeCodeStatus.Error(_localizer["The one time code was not correct."], CheckOneTimeCodeStatusCode.CodeIncorrect))); }