1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-25 12:45:18 +01:00

hibp api v3

This commit is contained in:
Kyle Spearrin 2019-07-22 21:23:09 -04:00
parent 2c80e337ae
commit b21e89f264
2 changed files with 30 additions and 9 deletions

View File

@ -8,6 +8,7 @@ using Bit.Core.Services;
using Bit.Core; using Bit.Core;
using System.Net; using System.Net;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using System.Linq;
namespace Bit.Api.Controllers namespace Bit.Api.Controllers
{ {
@ -15,17 +16,18 @@ namespace Bit.Api.Controllers
[Authorize("Application")] [Authorize("Application")]
public class HibpController : Controller public class HibpController : Controller
{ {
private const string HibpBreachApi = "https://haveibeenpwned.com/api/v2/breachedaccount/{0}"; private const string HibpBreachApi = "https://haveibeenpwned.com/api/v3/breachedaccount/{0}" +
"?truncateResponse=false&includeUnverified=false";
private static HttpClient _httpClient; private static HttpClient _httpClient;
private readonly IUserService _userService; private readonly IUserService _userService;
private readonly CurrentContext _currentContext; private readonly CurrentContext _currentContext;
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;
private readonly string _userAgent;
static HibpController() static HibpController()
{ {
_httpClient = new HttpClient(); _httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("User-Agent", "Bitwarden");
} }
public HibpController( public HibpController(
@ -36,19 +38,24 @@ namespace Bit.Api.Controllers
_userService = userService; _userService = userService;
_currentContext = currentContext; _currentContext = currentContext;
_globalSettings = globalSettings; _globalSettings = globalSettings;
_userAgent = _globalSettings.SelfHosted ? "Bitwarden Self-Hosted" : "Bitwarden";
} }
[HttpGet("breach")] [HttpGet("breach")]
public async Task<IActionResult> Get(string username) public async Task<IActionResult> Get(string username)
{ {
var encodedUsername = WebUtility.UrlEncode(username); return await SendAsync(WebUtility.UrlEncode(username), true);
var request = new HttpRequestMessage(HttpMethod.Get, string.Format(HibpBreachApi, encodedUsername));
if(!string.IsNullOrWhiteSpace(_globalSettings.HibpBreachApiKey))
{
request.Headers.Add("Authorization", $"Basic {_globalSettings.HibpBreachApiKey}");
} }
request.Headers.Add("Client-Id", GetClientId());
request.Headers.Add("Client-Ip", _currentContext.IpAddress); private async Task<IActionResult> SendAsync(string username, bool retry)
{
var request = new HttpRequestMessage(HttpMethod.Get, string.Format(HibpBreachApi, username));
if(!string.IsNullOrWhiteSpace(_globalSettings.HibpApiKey))
{
request.Headers.Add("hibp-api-key", _globalSettings.HibpApiKey);
}
request.Headers.Add("hibp-client-id", GetClientId());
request.Headers.Add("User-Agent", _userAgent);
var response = await _httpClient.SendAsync(request); var response = await _httpClient.SendAsync(request);
if(response.IsSuccessStatusCode) if(response.IsSuccessStatusCode)
{ {
@ -59,6 +66,20 @@ namespace Bit.Api.Controllers
{ {
return new NotFoundResult(); return new NotFoundResult();
} }
else if(response.StatusCode == HttpStatusCode.TooManyRequests && retry)
{
var delay = 2000;
if(response.Headers.Contains("retry-after"))
{
var vals = response.Headers.GetValues("retry-after");
if(vals.Any() && int.TryParse(vals.FirstOrDefault(), out var secDelay))
{
delay = (secDelay * 1000) + 200;
}
}
await Task.Delay(delay);
return await SendAsync(username, false);
}
else else
{ {
throw new BadRequestException("Request failed. Status code: " + response.StatusCode); throw new BadRequestException("Request failed. Status code: " + response.StatusCode);

View File

@ -14,7 +14,7 @@ namespace Bit.Core
public string LicenseCertificatePassword { get; set; } public string LicenseCertificatePassword { get; set; }
public virtual string PushRelayBaseUri { get; set; } public virtual string PushRelayBaseUri { get; set; }
public virtual string InternalIdentityKey { get; set; } public virtual string InternalIdentityKey { get; set; }
public virtual string HibpBreachApiKey { get; set; } public virtual string HibpApiKey { get; set; }
public virtual bool DisableUserRegistration { get; set; } public virtual bool DisableUserRegistration { get; set; }
public virtual bool DisableEmailNewDevice { get; set; } public virtual bool DisableEmailNewDevice { get; set; }
public virtual int OrganizationInviteExpirationHours { get; set; } = 120; // 5 days public virtual int OrganizationInviteExpirationHours { get; set; } = 120; // 5 days