public async Task <Response <Models.TrustedBrowser, Status> > AddTrustedBrowserAsync(string subjectId, string browserId, string description) { _logger.LogDebug("Adding trusted browser"); if (string.IsNullOrEmpty(subjectId) || string.IsNullOrEmpty(browserId)) { _logger.LogDebug("Subject id or browser id was missing."); return(Response.Error <Models.TrustedBrowser>(_localizer["Subject id or browser id was missing."])); } var dbBrowser = new TrustedBrowser() { SubjectId = subjectId, BrowserIdHash = FastHashService.GetHash(browserId, subjectId), Description = description?.Substring(0, description.Length), AddedOn = DateTime.UtcNow, }; await _context.AddAsync(dbBrowser); var count = await _context.SaveChangesAsync(); if (count == 0) { return(Response.Error <Models.TrustedBrowser>(_localizer["Failed to save trusted browser."])); } return(Response.Success(dbBrowser.ToModel(), _localizer["Trusted browser saved."])); }
public async Task <Response <Models.TrustedBrowser, Status> > GetTrustedBrowserAsync(string subjectId, string browserId) { _logger.LogDebug("Looking for trusted browser."); if (string.IsNullOrEmpty(subjectId) || string.IsNullOrEmpty(browserId)) { _logger.LogDebug("Subject id or browser id was missing."); return(Response.Error <Models.TrustedBrowser>(_localizer["Subject id or browser id was missing."])); } var browserIdHash = FastHashService.GetHash(browserId, subjectId); var model = (await _context.TrustedBrowsers.SingleOrDefaultAsync(x => x.BrowserIdHash == browserIdHash))?.ToModel(); if (model == null) { _logger.LogDebug("Trusted browser was not found."); return(Response.Error <Models.TrustedBrowser>(_localizer["Trusted browser was not found."])); } _logger.LogDebug("Trusted browser was found."); return(Response.Success(model, _localizer["Trusted browser found."])); }
public async Task <Response <GetOneTimeCodeResult, GetOneTimeCodeStatus> > GetOneTimeCodeAsync(string sendTo, TimeSpan validity, string redirectUrl = null) { var response = await _oneTimeCodeStore.GetOneTimeCodeAsync(sendTo); var otc = response.Result; if (otc != null && otc.ExpiresUTC > DateTime.UtcNow.AddMinutes(PasswordlessLoginConstants.OneTimeCode.IssueNewCodeIfValidityLessThanXMinutes) && otc.ExpiresUTC < DateTime.UtcNow.AddMinutes(_options.OneTimeCodeValidityMinutes)) { _logger.LogDebug("A once time code exists that has enough time left to use"); // existing code has at least X minutes of validity remaining, so resend it // if more than default validity (e.g. first code sent to new user), user could accidentally // lock the code and not be able to confirm or access the account (terrible UX) if (otc.SentCount >= PasswordlessLoginConstants.OneTimeCode.MaxResendCount) { _logger.LogDebug("The existing one time code has been sent too many times."); return(new Response <GetOneTimeCodeResult, GetOneTimeCodeStatus>( GetOneTimeCodeStatus.Error(_localizer["Too many requests."], GetOneTimeCodeStatusCode.TooManyRequests))); } _logger.LogDebug("Updating the record of how many times the code has been sent"); await _oneTimeCodeStore.UpdateOneTimeCodeSentCountAsync(sendTo, otc.SentCount + 1, redirectUrl); _logger.LogDebug("Returning the still valid code without a client nonce, which can only be delivered once."); return(new Response <GetOneTimeCodeResult, GetOneTimeCodeStatus>( new GetOneTimeCodeResult { ClientNonce = null, // only given out when code is first generated ShortCode = otc.ShortCode, LongCode = otc.LongCode }, GetOneTimeCodeStatus.Success(_localizer["One time code found."]))); } _logger.LogDebug("Generating a new one time code, link, and client nonce."); var rngProvider = new RNGCryptoServiceProvider(); var byteArray = new byte[8]; rngProvider.GetBytes(byteArray); var clientNonceUInt = BitConverter.ToUInt64(byteArray, 0); var clientNonce = clientNonceUInt.ToString(); var clientNonceHash = FastHashService.GetHash(clientNonce, sendTo); rngProvider.GetBytes(byteArray); var longCodeUInt = BitConverter.ToUInt64(byteArray, 0); var longCode = longCodeUInt.ToString(); var shortCode = (longCodeUInt % 1000000).ToString("000000"); otc = new OneTimeCode() { SentTo = sendTo, ClientNonceHash = clientNonceHash, ShortCode = shortCode, ExpiresUTC = DateTime.UtcNow.Add(validity), LongCode = longCode, RedirectUrl = redirectUrl, FailedAttemptCount = 0, SentCount = 1 }; await _oneTimeCodeStore.RemoveOneTimeCodeAsync(sendTo); var codeSavedStatus = await _oneTimeCodeStore.AddOneTimeCodeAsync(otc); if (codeSavedStatus.HasError) { _logger.LogError("Failed to store the code."); return(new Response <GetOneTimeCodeResult, GetOneTimeCodeStatus>( GetOneTimeCodeStatus.Error(_localizer["Failed to save the one time code."], GetOneTimeCodeStatusCode.ServiceFailure))); } return(new Response <GetOneTimeCodeResult, GetOneTimeCodeStatus>( new GetOneTimeCodeResult { ClientNonce = clientNonce, ShortCode = shortCode, LongCode = longCode }, GetOneTimeCodeStatus.Success(_localizer["One time code was generated."]))); }