mirror of
https://github.com/bitwarden/server
synced 2025-12-31 07:33:43 +00:00
PM-19715 & PM-19712 Move Files to DIRT ownership on Server (#5769)
* PM-19715 PM-19711 moving reports to dirt directory and adding dirt as codeowners * PM-19715 creating two sub folders for reports and events * PM-19714 changing dirt paths for codeowners * PM-19714 fixing codeowners file * PM-19714 fixing codeowners * PM-19714 moving hibpController to dirt ownership * PM-19715 moving controller
This commit is contained in:
@@ -1,97 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.Tools.Controllers;
|
||||
|
||||
[Route("hibp")]
|
||||
[Authorize("Application")]
|
||||
public class HibpController : Controller
|
||||
{
|
||||
private const string HibpBreachApi = "https://haveibeenpwned.com/api/v3/breachedaccount/{0}" +
|
||||
"?truncateResponse=false&includeUnverified=false";
|
||||
private static HttpClient _httpClient;
|
||||
|
||||
private readonly IUserService _userService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly string _userAgent;
|
||||
|
||||
static HibpController()
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
}
|
||||
|
||||
public HibpController(
|
||||
IUserService userService,
|
||||
ICurrentContext currentContext,
|
||||
GlobalSettings globalSettings)
|
||||
{
|
||||
_userService = userService;
|
||||
_currentContext = currentContext;
|
||||
_globalSettings = globalSettings;
|
||||
_userAgent = _globalSettings.SelfHosted ? "Bitwarden Self-Hosted" : "Bitwarden";
|
||||
}
|
||||
|
||||
[HttpGet("breach")]
|
||||
public async Task<IActionResult> Get(string username)
|
||||
{
|
||||
return await SendAsync(WebUtility.UrlEncode(username), true);
|
||||
}
|
||||
|
||||
private async Task<IActionResult> SendAsync(string username, bool retry)
|
||||
{
|
||||
if (!CoreHelpers.SettingHasValue(_globalSettings.HibpApiKey))
|
||||
{
|
||||
throw new BadRequestException("HaveIBeenPwned API key not set.");
|
||||
}
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, string.Format(HibpBreachApi, username));
|
||||
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);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var data = await response.Content.ReadAsStringAsync();
|
||||
return Content(data, "application/json");
|
||||
}
|
||||
else if (response.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
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
|
||||
{
|
||||
throw new BadRequestException("Request failed. Status code: " + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetClientId()
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
using (var sha256 = SHA256.Create())
|
||||
{
|
||||
var hash = sha256.ComputeHash(userId.ToByteArray());
|
||||
return Convert.ToBase64String(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
using Bit.Api.Tools.Models;
|
||||
using Bit.Api.Tools.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Tools.Models.Data;
|
||||
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
||||
using Bit.Core.Tools.ReportFeatures.OrganizationReportMembers.Interfaces;
|
||||
using Bit.Core.Tools.ReportFeatures.Requests;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.Tools.Controllers;
|
||||
|
||||
[Route("reports")]
|
||||
[Authorize("Application")]
|
||||
public class ReportsController : Controller
|
||||
{
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IMemberAccessCipherDetailsQuery _memberAccessCipherDetailsQuery;
|
||||
private readonly IAddPasswordHealthReportApplicationCommand _addPwdHealthReportAppCommand;
|
||||
private readonly IGetPasswordHealthReportApplicationQuery _getPwdHealthReportAppQuery;
|
||||
private readonly IDropPasswordHealthReportApplicationCommand _dropPwdHealthReportAppCommand;
|
||||
|
||||
public ReportsController(
|
||||
ICurrentContext currentContext,
|
||||
IMemberAccessCipherDetailsQuery memberAccessCipherDetailsQuery,
|
||||
IAddPasswordHealthReportApplicationCommand addPasswordHealthReportApplicationCommand,
|
||||
IGetPasswordHealthReportApplicationQuery getPasswordHealthReportApplicationQuery,
|
||||
IDropPasswordHealthReportApplicationCommand dropPwdHealthReportAppCommand
|
||||
)
|
||||
{
|
||||
_currentContext = currentContext;
|
||||
_memberAccessCipherDetailsQuery = memberAccessCipherDetailsQuery;
|
||||
_addPwdHealthReportAppCommand = addPasswordHealthReportApplicationCommand;
|
||||
_getPwdHealthReportAppQuery = getPasswordHealthReportApplicationQuery;
|
||||
_dropPwdHealthReportAppCommand = dropPwdHealthReportAppCommand;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Organization member information containing a list of cipher ids
|
||||
/// assigned
|
||||
/// </summary>
|
||||
/// <param name="orgId">Organzation Id</param>
|
||||
/// <returns>IEnumerable of MemberCipherDetailsResponseModel</returns>
|
||||
/// <exception cref="NotFoundException">If Access reports permission is not assigned</exception>
|
||||
[HttpGet("member-cipher-details/{orgId}")]
|
||||
public async Task<IEnumerable<MemberCipherDetailsResponseModel>> GetMemberCipherDetails(Guid orgId)
|
||||
{
|
||||
// Using the AccessReports permission here until new permissions
|
||||
// are needed for more control over reports
|
||||
if (!await _currentContext.AccessReports(orgId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var memberCipherDetails = await GetMemberCipherDetails(new MemberAccessCipherDetailsRequest { OrganizationId = orgId });
|
||||
|
||||
var responses = memberCipherDetails.Select(x => new MemberCipherDetailsResponseModel(x));
|
||||
|
||||
return responses;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Access details for an organization member. Includes the member information,
|
||||
/// group collection assignment, and item counts
|
||||
/// </summary>
|
||||
/// <param name="orgId">Organization Id</param>
|
||||
/// <returns>IEnumerable of MemberAccessReportResponseModel</returns>
|
||||
/// <exception cref="NotFoundException">If Access reports permission is not assigned</exception>
|
||||
[HttpGet("member-access/{orgId}")]
|
||||
public async Task<IEnumerable<MemberAccessReportResponseModel>> GetMemberAccessReport(Guid orgId)
|
||||
{
|
||||
if (!await _currentContext.AccessReports(orgId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var memberCipherDetails = await GetMemberCipherDetails(new MemberAccessCipherDetailsRequest { OrganizationId = orgId });
|
||||
|
||||
var responses = memberCipherDetails.Select(x => new MemberAccessReportResponseModel(x));
|
||||
|
||||
return responses;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains the organization member info, the cipher ids associated with the member,
|
||||
/// and details on their collections, groups, and permissions
|
||||
/// </summary>
|
||||
/// <param name="request">Request to the MemberAccessCipherDetailsQuery</param>
|
||||
/// <returns>IEnumerable of MemberAccessCipherDetails</returns>
|
||||
private async Task<IEnumerable<MemberAccessCipherDetails>> GetMemberCipherDetails(MemberAccessCipherDetailsRequest request)
|
||||
{
|
||||
var memberCipherDetails =
|
||||
await _memberAccessCipherDetailsQuery.GetMemberAccessCipherDetails(request);
|
||||
return memberCipherDetails;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the password health report applications for an organization
|
||||
/// </summary>
|
||||
/// <param name="orgId">A valid Organization Id</param>
|
||||
/// <returns>An Enumerable of PasswordHealthReportApplication </returns>
|
||||
/// <exception cref="NotFoundException">If the user lacks access</exception>
|
||||
/// <exception cref="BadRequestException">If the organization Id is not valid</exception>
|
||||
[HttpGet("password-health-report-applications/{orgId}")]
|
||||
public async Task<IEnumerable<PasswordHealthReportApplication>> GetPasswordHealthReportApplications(Guid orgId)
|
||||
{
|
||||
if (!await _currentContext.AccessReports(orgId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return await _getPwdHealthReportAppQuery.GetPasswordHealthReportApplicationAsync(orgId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new record into PasswordHealthReportApplication
|
||||
/// </summary>
|
||||
/// <param name="request">A single instance of PasswordHealthReportApplication Model</param>
|
||||
/// <returns>A single instance of PasswordHealthReportApplication</returns>
|
||||
/// <exception cref="BadRequestException">If the organization Id is not valid</exception>
|
||||
/// <exception cref="NotFoundException">If the user lacks access</exception>
|
||||
[HttpPost("password-health-report-application")]
|
||||
public async Task<PasswordHealthReportApplication> AddPasswordHealthReportApplication(
|
||||
[FromBody] PasswordHealthReportApplicationModel request)
|
||||
{
|
||||
if (!await _currentContext.AccessReports(request.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var commandRequest = new AddPasswordHealthReportApplicationRequest
|
||||
{
|
||||
OrganizationId = request.OrganizationId,
|
||||
Url = request.Url
|
||||
};
|
||||
|
||||
return await _addPwdHealthReportAppCommand.AddPasswordHealthReportApplicationAsync(commandRequest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple records into PasswordHealthReportApplication
|
||||
/// </summary>
|
||||
/// <param name="request">A enumerable of PasswordHealthReportApplicationModel</param>
|
||||
/// <returns>An Enumerable of PasswordHealthReportApplication</returns>
|
||||
/// <exception cref="NotFoundException">If user does not have access to the OrganizationId</exception>
|
||||
/// <exception cref="BadRequestException">If the organization Id is not valid</exception>
|
||||
[HttpPost("password-health-report-applications")]
|
||||
public async Task<IEnumerable<PasswordHealthReportApplication>> AddPasswordHealthReportApplications(
|
||||
[FromBody] IEnumerable<PasswordHealthReportApplicationModel> request)
|
||||
{
|
||||
if (request.Any(_ => _currentContext.AccessReports(_.OrganizationId).Result == false))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var commandRequests = request.Select(request => new AddPasswordHealthReportApplicationRequest
|
||||
{
|
||||
OrganizationId = request.OrganizationId,
|
||||
Url = request.Url
|
||||
}).ToList();
|
||||
|
||||
return await _addPwdHealthReportAppCommand.AddPasswordHealthReportApplicationAsync(commandRequests);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops a record from PasswordHealthReportApplication
|
||||
/// </summary>
|
||||
/// <param name="request">
|
||||
/// A single instance of DropPasswordHealthReportApplicationRequest
|
||||
/// { OrganizationId, array of PasswordHealthReportApplicationIds }
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotFoundException">If user does not have access to the organization</exception>
|
||||
/// <exception cref="BadRequestException">If the organization does not have any records</exception>
|
||||
[HttpDelete("password-health-report-application")]
|
||||
public async Task DropPasswordHealthReportApplication(
|
||||
[FromBody] DropPasswordHealthReportApplicationRequest request)
|
||||
{
|
||||
if (!await _currentContext.AccessReports(request.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
await _dropPwdHealthReportAppCommand.DropPasswordHealthReportApplicationAsync(request);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user