audit service

This commit is contained in:
Kyle Spearrin 2019-04-17 17:10:21 -04:00
parent 6d159740d9
commit 676e896d8c
5 changed files with 106 additions and 0 deletions

View File

@ -2,6 +2,7 @@
using Bit.Core.Models.Request;
using Bit.Core.Models.Response;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
@ -42,5 +43,6 @@ namespace Bit.Core.Abstractions
Task<CipherResponse> PostCipherAttachmentAsync(string id, MultipartFormDataContent data);
Task PostShareCipherAttachmentAsync(string id, string attachmentId, MultipartFormDataContent data,
string organizationId);
Task<List<BreachAccountResponse>> GetHibpBreachAsync(string username);
}
}

View File

@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Models.Response;
namespace Bit.Core.Abstractions
{
public interface IAuditService
{
Task<List<BreachAccountResponse>> BreachedAccountsAsync(string username);
Task<int> PasswordLeakedAsync(string password);
}
}

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
namespace Bit.Core.Models.Response
{
public class BreachAccountResponse
{
public string AddedDate { get; set; }
public string BreachDate { get; set; }
public List<string> DataClasses { get; set; }
public string Description { get; set; }
public string Domain { get; set; }
public bool IsActive { get; set; }
public bool IsVerified { get; set; }
public string LogoPath { get; set; }
public string ModifiedDate { get; set; }
public string Name { get; set; }
public int PwnCount { get; set; }
public string Title { get; set; }
}
}

View File

@ -261,6 +261,16 @@ namespace Bit.Core.Services
#endregion
#region HIBP APIs
public Task<List<BreachAccountResponse>> GetHibpBreachAsync(string username)
{
return SendAsync<object, List<BreachAccountResponse>>(HttpMethod.Get,
string.Concat("/hibp/breach?username=", username), null, true, true);
}
#endregion
#region Helpers
public async Task<string> GetActiveBearerTokenAsync()

View File

@ -0,0 +1,62 @@
using Bit.Core.Abstractions;
using Bit.Core.Exceptions;
using Bit.Core.Models.Response;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Bit.Core.Services
{
public class AuditService : IAuditService
{
private const string PwnedPasswordsApi = "https://api.pwnedpasswords.com/range/";
private readonly ICryptoFunctionService _cryptoFunctionService;
private readonly IApiService _apiService;
private HttpClient _httpClient;
public AuditService(
ICryptoFunctionService cryptoFunctionService,
IApiService apiService)
{
_cryptoFunctionService = cryptoFunctionService;
_apiService = apiService;
}
public async Task<int> PasswordLeakedAsync(string password)
{
var hashBytes = await _cryptoFunctionService.HashAsync(password, Enums.CryptoHashAlgorithm.Sha1);
var hash = BitConverter.ToString(hashBytes).ToUpperInvariant();
var hashStart = hash.Substring(0, 5);
var hashEnding = hash.Substring(5);
var response = await _httpClient.GetAsync(string.Concat(PwnedPasswordsApi, hashStart));
var leakedHashes = await response.Content.ReadAsStringAsync();
var match = leakedHashes.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
.FirstOrDefault(v => v.Split(':')[0] == hashEnding);
if(match != null && int.TryParse(match.Split(':')[1], out var matchCount))
{
return matchCount;
}
return 0;
}
public async Task<List<BreachAccountResponse>> BreachedAccountsAsync(string username)
{
try
{
return await _apiService.GetHibpBreachAsync(username);
}
catch(ApiException e)
{
if(e.Error != null && e.Error.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return new List<BreachAccountResponse>();
}
throw e;
}
}
}
}