1
0
mirror of https://github.com/bitwarden/server synced 2025-12-06 00:03:34 +00:00

[SM-1575] Add ability to retrieve events based on projectId/SecretId (#6316)

* adding event filters

* allow user to see deleted secret event logs through public api

* nullable changes to event controller

* fixing tests

* fixing permissions issues with public API

* fix for bug

* Update src/Api/AdminConsole/Public/Controllers/EventsController.cs

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Update src/Api/AdminConsole/Public/Controllers/EventsController.cs

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
This commit is contained in:
cd-bitwarden
2025-11-14 18:21:48 -05:00
committed by GitHub
parent 7eaca9bb7d
commit 1274fe6562
2 changed files with 65 additions and 8 deletions

View File

@@ -1,6 +1,4 @@
// FIXME: Update this file to be null safe and then delete the line below
#nullable disable

using System.Net;
using Bit.Api.Models.Public.Request;
using Bit.Api.Models.Public.Response;
@@ -8,6 +6,7 @@ using Bit.Api.Utilities.DiagnosticTools;
using Bit.Core.Context;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.SecretsManager.Repositories;
using Bit.Core.Services;
using Bit.Core.Vault.Repositories;
using Microsoft.AspNetCore.Authorization;
@@ -22,6 +21,9 @@ public class EventsController : Controller
private readonly IEventRepository _eventRepository;
private readonly ICipherRepository _cipherRepository;
private readonly ICurrentContext _currentContext;
private readonly ISecretRepository _secretRepository;
private readonly IProjectRepository _projectRepository;
private readonly IUserService _userService;
private readonly ILogger<EventsController> _logger;
private readonly IFeatureService _featureService;
@@ -29,12 +31,18 @@ public class EventsController : Controller
IEventRepository eventRepository,
ICipherRepository cipherRepository,
ICurrentContext currentContext,
ISecretRepository secretRepository,
IProjectRepository projectRepository,
IUserService userService,
ILogger<EventsController> logger,
IFeatureService featureService)
{
_eventRepository = eventRepository;
_cipherRepository = cipherRepository;
_currentContext = currentContext;
_secretRepository = secretRepository;
_projectRepository = projectRepository;
_userService = userService;
_logger = logger;
_featureService = featureService;
}
@@ -50,35 +58,76 @@ public class EventsController : Controller
[ProducesResponseType(typeof(PagedListResponseModel<EventResponseModel>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> List([FromQuery] EventFilterRequestModel request)
{
if (!_currentContext.OrganizationId.HasValue)
{
return new JsonResult(new PagedListResponseModel<EventResponseModel>([], ""));
}
var organizationId = _currentContext.OrganizationId.Value;
var dateRange = request.ToDateRange();
var result = new PagedResult<IEvent>();
if (request.ActingUserId.HasValue)
{
result = await _eventRepository.GetManyByOrganizationActingUserAsync(
_currentContext.OrganizationId.Value, request.ActingUserId.Value, dateRange.Item1, dateRange.Item2,
organizationId, request.ActingUserId.Value, dateRange.Item1, dateRange.Item2,
new PageOptions { ContinuationToken = request.ContinuationToken });
}
else if (request.ItemId.HasValue)
{
var cipher = await _cipherRepository.GetByIdAsync(request.ItemId.Value);
if (cipher != null && cipher.OrganizationId == _currentContext.OrganizationId.Value)
if (cipher != null && cipher.OrganizationId == organizationId)
{
result = await _eventRepository.GetManyByCipherAsync(
cipher, dateRange.Item1, dateRange.Item2,
new PageOptions { ContinuationToken = request.ContinuationToken });
}
}
else if (request.SecretId.HasValue)
{
var secret = await _secretRepository.GetByIdAsync(request.SecretId.Value);
if (secret == null)
{
secret = new Core.SecretsManager.Entities.Secret { Id = request.SecretId.Value, OrganizationId = organizationId };
}
if (secret.OrganizationId == organizationId)
{
result = await _eventRepository.GetManyBySecretAsync(
secret, dateRange.Item1, dateRange.Item2,
new PageOptions { ContinuationToken = request.ContinuationToken });
}
else
{
return new JsonResult(new PagedListResponseModel<EventResponseModel>([], ""));
}
}
else if (request.ProjectId.HasValue)
{
var project = await _projectRepository.GetByIdAsync(request.ProjectId.Value);
if (project != null && project.OrganizationId == organizationId)
{
result = await _eventRepository.GetManyByProjectAsync(
project, dateRange.Item1, dateRange.Item2,
new PageOptions { ContinuationToken = request.ContinuationToken });
}
else
{
return new JsonResult(new PagedListResponseModel<EventResponseModel>([], ""));
}
}
else
{
result = await _eventRepository.GetManyByOrganizationAsync(
_currentContext.OrganizationId.Value, dateRange.Item1, dateRange.Item2,
organizationId, dateRange.Item1, dateRange.Item2,
new PageOptions { ContinuationToken = request.ContinuationToken });
}
var eventResponses = result.Data.Select(e => new EventResponseModel(e));
var response = new PagedListResponseModel<EventResponseModel>(eventResponses, result.ContinuationToken);
var response = new PagedListResponseModel<EventResponseModel>(eventResponses, result.ContinuationToken ?? "");
_logger.LogAggregateData(_featureService, organizationId, response, request);
_logger.LogAggregateData(_featureService, _currentContext.OrganizationId!.Value, response, request);
return new JsonResult(response);
}
}

View File

@@ -24,6 +24,14 @@ public class EventFilterRequestModel
/// </summary>
public Guid? ItemId { get; set; }
/// <summary>
/// The unique identifier of the related secret that the event describes.
/// </summary>
public Guid? SecretId { get; set; }
/// <summary>
/// The unique identifier of the related project that the event describes.
/// </summary>
public Guid? ProjectId { get; set; }
/// <summary>
/// A cursor for use in pagination.
/// </summary>
public string ContinuationToken { get; set; }