1
0
mirror of https://github.com/bitwarden/server synced 2026-01-15 06:53:26 +00:00

Resolve review feedback

This commit is contained in:
Hinton
2025-12-19 13:48:57 +01:00
parent afce475833
commit ba879fd872
12 changed files with 243 additions and 71 deletions

View File

@@ -29,6 +29,14 @@ public class NeverPlayIdServices : IPlayIdService
}
}
/// <summary>
/// Singleton wrapper service that bridges singleton-scoped service boundaries for PlayId tracking.
/// This allows singleton services to access the scoped PlayIdService via HttpContext.RequestServices.
///
/// Uses IHttpContextAccessor to retrieve the current request's scoped PlayIdService instance, enabling
/// singleton services to participate in Play session tracking without violating DI lifetime rules.
/// Falls back to NeverPlayIdServices when no HttpContext is available (e.g., background jobs).
/// </summary>
public class PlayIdSingletonService(IHttpContextAccessor httpContextAccessor, IHostEnvironment hostEnvironment) : IPlayIdService
{
private IPlayIdService Current

View File

@@ -9,7 +9,6 @@ using Bit.Core.NotificationCenter.Repositories;
using Bit.Core.Platform.Installations;
using Bit.Core.Repositories;
using Bit.Core.SecretsManager.Repositories;
using Bit.Core.Settings;
using Bit.Core.Tools.Repositories;
using Bit.Core.Vault.Repositories;
using Bit.Infrastructure.Dapper.AdminConsole.Repositories;
@@ -29,19 +28,8 @@ namespace Bit.Infrastructure.Dapper;
public static class DapperServiceCollectionExtensions
{
public static void AddDapperRepositories(this IServiceCollection services, bool selfHosted, GlobalSettings globalSettings)
public static void AddDapperRepositories(this IServiceCollection services, bool selfHosted)
{
if (globalSettings.TestPlayIdTrackingEnabled)
{
services.AddSingleton<IOrganizationRepository, TestOrganizationTrackingOrganizationRepository>();
services.AddSingleton<IUserRepository, TestUserTrackingUserRepository>();
}
else
{
services.AddSingleton<IOrganizationRepository, OrganizationRepository>();
services.AddSingleton<IUserRepository, UserRepository>();
}
services.AddSingleton<IApiKeyRepository, ApiKeyRepository>();
services.AddSingleton<IAuthRequestRepository, AuthRequestRepository>();
services.AddSingleton<ICipherRepository, CipherRepository>();
@@ -59,6 +47,7 @@ public static class DapperServiceCollectionExtensions
services.AddSingleton<IOrganizationConnectionRepository, OrganizationConnectionRepository>();
services.AddSingleton<IOrganizationIntegrationConfigurationRepository, OrganizationIntegrationConfigurationRepository>();
services.AddSingleton<IOrganizationIntegrationRepository, OrganizationIntegrationRepository>();
services.AddSingleton<IOrganizationRepository, OrganizationRepository>();
services.AddSingleton<IOrganizationSponsorshipRepository, OrganizationSponsorshipRepository>();
services.AddSingleton<IOrganizationUserRepository, OrganizationUserRepository>();
services.AddSingleton<IPlayDataRepository, PlayDataRepository>();
@@ -70,6 +59,7 @@ public static class DapperServiceCollectionExtensions
services.AddSingleton<ISsoConfigRepository, SsoConfigRepository>();
services.AddSingleton<ISsoUserRepository, SsoUserRepository>();
services.AddSingleton<ITransactionRepository, TransactionRepository>();
services.AddSingleton<IUserRepository, UserRepository>();
services.AddSingleton<IOrganizationDomainRepository, OrganizationDomainRepository>();
services.AddSingleton<IWebAuthnCredentialRepository, WebAuthnCredentialRepository>();
services.AddSingleton<IProviderPlanRepository, ProviderPlanRepository>();
@@ -92,4 +82,15 @@ public static class DapperServiceCollectionExtensions
services.AddSingleton<IEventRepository, EventRepository>();
}
}
/// <summary>
/// Adds PlayId tracking decorators for User and Organization repositories.
/// This replaces the standard repository implementations with tracking versions
/// that record created entities for test data cleanup. Only call when TestPlayIdTrackingEnabled is true.
/// </summary>
public static void AddPlayIdTrackingRepositories(this IServiceCollection services)
{
services.AddSingleton<IOrganizationRepository, TestOrganizationTrackingOrganizationRepository>();
services.AddSingleton<IUserRepository, TestUserTrackingUserRepository>();
}
}

View File

@@ -68,19 +68,8 @@ public static class EntityFrameworkServiceCollectionExtensions
});
}
public static void AddPasswordManagerEFRepositories(this IServiceCollection services, bool selfHosted, GlobalSettings globalSettings)
public static void AddPasswordManagerEFRepositories(this IServiceCollection services, bool selfHosted)
{
if (globalSettings.TestPlayIdTrackingEnabled)
{
services.AddSingleton<IOrganizationRepository, TestOrganizationTrackingOrganizationRepository>();
services.AddSingleton<IUserRepository, TestUserTrackingUserRepository>();
}
else
{
services.AddSingleton<IOrganizationRepository, OrganizationRepository>();
services.AddSingleton<IUserRepository, UserRepository>();
}
services.AddSingleton<IApiKeyRepository, ApiKeyRepository>();
services.AddSingleton<IAuthRequestRepository, AuthRequestRepository>();
services.AddSingleton<ICipherRepository, CipherRepository>();
@@ -97,6 +86,7 @@ public static class EntityFrameworkServiceCollectionExtensions
services.AddSingleton<IOrganizationConnectionRepository, OrganizationConnectionRepository>();
services.AddSingleton<IOrganizationIntegrationRepository, OrganizationIntegrationRepository>();
services.AddSingleton<IOrganizationIntegrationConfigurationRepository, OrganizationIntegrationConfigurationRepository>();
services.AddSingleton<IOrganizationRepository, OrganizationRepository>();
services.AddSingleton<IOrganizationSponsorshipRepository, OrganizationSponsorshipRepository>();
services.AddSingleton<IOrganizationUserRepository, OrganizationUserRepository>();
services.AddSingleton<IPlayDataRepository, PlayDataRepository>();
@@ -108,6 +98,7 @@ public static class EntityFrameworkServiceCollectionExtensions
services.AddSingleton<ISsoConfigRepository, SsoConfigRepository>();
services.AddSingleton<ISsoUserRepository, SsoUserRepository>();
services.AddSingleton<ITransactionRepository, TransactionRepository>();
services.AddSingleton<IUserRepository, UserRepository>();
services.AddSingleton<IOrganizationDomainRepository, OrganizationDomainRepository>();
services.AddSingleton<IWebAuthnCredentialRepository, WebAuthnCredentialRepository>();
services.AddSingleton<IProviderPlanRepository, ProviderPlanRepository>();
@@ -130,4 +121,15 @@ public static class EntityFrameworkServiceCollectionExtensions
services.AddSingleton<IEventRepository, EventRepository>();
}
}
/// <summary>
/// Adds PlayId tracking decorators for User and Organization repositories.
/// This replaces the standard repository implementations with tracking versions
/// that record created entities for test data cleanup. Only call when TestPlayIdTrackingEnabled is true.
/// </summary>
public static void AddPlayIdTrackingEFRepositories(this IServiceCollection services)
{
services.AddSingleton<IOrganizationRepository, TestOrganizationTrackingOrganizationRepository>();
services.AddSingleton<IUserRepository, TestUserTrackingUserRepository>();
}
}

View File

@@ -11,13 +11,31 @@ namespace Bit.SharedWeb.Utilities;
/// <param name="next"></param>
public sealed class PlayIdMiddleware(RequestDelegate next)
{
public Task Invoke(HttpContext context, PlayIdService playIdService)
private const int MaxPlayIdLength = 256;
public async Task Invoke(HttpContext context, PlayIdService playIdService)
{
if (context.Request.Headers.TryGetValue("x-play-id", out var playId))
{
playIdService.PlayId = playId;
var playIdValue = playId.ToString();
if (string.IsNullOrWhiteSpace(playIdValue))
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
await context.Response.WriteAsJsonAsync(new { Error = "x-play-id header cannot be empty or whitespace" });
return;
}
if (playIdValue.Length > MaxPlayIdLength)
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
await context.Response.WriteAsJsonAsync(new { Error = $"x-play-id header cannot exceed {MaxPlayIdLength} characters" });
return;
}
playIdService.PlayId = playIdValue;
}
return next(context);
await next(context);
}
}

View File

@@ -96,11 +96,11 @@ public static class ServiceCollectionExtensions
if (provider != SupportedDatabaseProviders.SqlServer)
{
services.AddPasswordManagerEFRepositories(globalSettings.SelfHosted, globalSettings);
services.AddPasswordManagerEFRepositories(globalSettings.SelfHosted);
}
else
{
services.AddDapperRepositories(globalSettings.SelfHosted, globalSettings);
services.AddDapperRepositories(globalSettings.SelfHosted);
}
if (globalSettings.SelfHosted)
@@ -123,6 +123,16 @@ public static class ServiceCollectionExtensions
services.AddSingleton<IPlayDataService, PlayDataService>();
services.AddSingleton<IPlayIdService, PlayIdSingletonService>();
services.AddScoped<PlayIdService>();
// Replace standard repositories with PlayId tracking decorators
if (provider == SupportedDatabaseProviders.SqlServer)
{
services.AddPlayIdTrackingRepositories();
}
else
{
services.AddPlayIdTrackingEFRepositories();
}
}
else
{

View File

@@ -5,7 +5,11 @@ BEGIN
SET NOCOUNT ON
SELECT
*
[Id],
[PlayId],
[UserId],
[OrganizationId],
[CreationDate]
FROM
[dbo].[PlayData]
WHERE