Files
server/src/Api/Controllers/HibpController.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

103 lines
3.6 KiB
C#
Raw Normal View History

2019-01-17 01:03:11 -05:00
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Bit.Core.Context;
2019-01-17 01:03:11 -05:00
using Bit.Core.Exceptions;
2019-07-27 12:29:20 -04:00
using Bit.Core.Services;
using Bit.Core.Settings;
2019-01-17 01:03:11 -05:00
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Bit.Api.Controllers
{
[Route("hibp")]
[Authorize("Application")]
public class HibpController : Controller
{
2019-07-22 21:23:09 -04:00
private const string HibpBreachApi = "https://haveibeenpwned.com/api/v3/breachedaccount/{0}" +
"?truncateResponse=false&includeUnverified=false";
2019-01-17 01:03:11 -05:00
private static HttpClient _httpClient;
private readonly IUserService _userService;
private readonly ICurrentContext _currentContext;
2019-01-17 01:03:11 -05:00
private readonly GlobalSettings _globalSettings;
2019-07-22 21:23:09 -04:00
private readonly string _userAgent;
2019-01-17 01:03:11 -05:00
static HibpController()
{
_httpClient = new HttpClient();
}
public HibpController(
IUserService userService,
ICurrentContext currentContext,
2019-01-17 01:03:11 -05:00
GlobalSettings globalSettings)
{
_userService = userService;
_currentContext = currentContext;
_globalSettings = globalSettings;
2019-07-22 21:23:09 -04:00
_userAgent = _globalSettings.SelfHosted ? "Bitwarden Self-Hosted" : "Bitwarden";
2019-01-17 01:03:11 -05:00
}
[HttpGet("breach")]
2019-01-17 01:06:03 -05:00
public async Task<IActionResult> Get(string username)
2019-01-17 01:03:11 -05:00
{
2019-07-22 21:23:09 -04:00
return await SendAsync(WebUtility.UrlEncode(username), true);
}
private async Task<IActionResult> SendAsync(string username, bool retry)
{
if (!CoreHelpers.SettingHasValue(_globalSettings.HibpApiKey))
2019-01-17 01:03:11 -05:00
{
2019-07-27 12:29:20 -04:00
throw new BadRequestException("HaveIBeenPwned API key not set.");
2019-01-17 01:03:11 -05:00
}
2019-07-27 12:29:20 -04:00
var request = new HttpRequestMessage(HttpMethod.Get, string.Format(HibpBreachApi, username));
request.Headers.Add("hibp-api-key", _globalSettings.HibpApiKey);
2019-07-22 21:23:09 -04:00
request.Headers.Add("hibp-client-id", GetClientId());
request.Headers.Add("User-Agent", _userAgent);
2019-01-17 01:03:11 -05:00
var response = await _httpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
2019-01-17 01:03:11 -05:00
{
var data = await response.Content.ReadAsStringAsync();
return Content(data, "application/json");
}
else if (response.StatusCode == HttpStatusCode.NotFound)
2019-01-17 01:03:11 -05:00
{
return new NotFoundResult();
}
else if (response.StatusCode == HttpStatusCode.TooManyRequests && retry)
2019-07-22 21:23:09 -04:00
{
var delay = 2000;
if (response.Headers.Contains("retry-after"))
2019-07-22 21:23:09 -04:00
{
var vals = response.Headers.GetValues("retry-after");
if (vals.Any() && int.TryParse(vals.FirstOrDefault(), out var secDelay))
2019-07-22 21:23:09 -04:00
{
delay = (secDelay * 1000) + 200;
}
}
await Task.Delay(delay);
return await SendAsync(username, false);
}
2019-01-17 01:03:11 -05:00
else
{
throw new BadRequestException("Request failed. Status code: " + response.StatusCode);
}
}
private string GetClientId()
{
var userId = _userService.GetProperUserId(User).Value;
using (var sha256 = SHA256.Create())
2019-01-17 01:03:11 -05:00
{
var hash = sha256.ComputeHash(userId.ToByteArray());
return Convert.ToBase64String(hash);
}
}
}
}