1
0
mirror of https://github.com/bitwarden/server synced 2026-01-15 15:03:34 +00:00

Merge remote-tracking branch 'origin' into auth/pm-22975/client-version-validator

This commit is contained in:
Patrick Pimentel
2026-01-02 13:32:18 -05:00
251 changed files with 24373 additions and 1133 deletions

View File

@@ -3,6 +3,7 @@ using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Update;
using Bit.Core.Billing.Organizations.Services;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;
@@ -162,8 +163,9 @@ public class OrganizationUpdateCommandTests
OrganizationId = organizationId,
Name = organization.Name,
BillingEmail = organization.BillingEmail,
PublicKey = publicKey,
EncryptedPrivateKey = encryptedPrivateKey
Keys = new PublicKeyEncryptionKeyPairData(
wrappedPrivateKey: encryptedPrivateKey,
publicKey: publicKey)
};
// Act
@@ -207,8 +209,9 @@ public class OrganizationUpdateCommandTests
OrganizationId = organizationId,
Name = organization.Name,
BillingEmail = organization.BillingEmail,
PublicKey = newPublicKey,
EncryptedPrivateKey = newEncryptedPrivateKey
Keys = new PublicKeyEncryptionKeyPairData(
wrappedPrivateKey: newEncryptedPrivateKey,
publicKey: newPublicKey)
};
// Act
@@ -394,8 +397,9 @@ public class OrganizationUpdateCommandTests
OrganizationId = organizationId,
Name = newName, // Should be ignored
BillingEmail = newBillingEmail, // Should be ignored
PublicKey = publicKey,
EncryptedPrivateKey = encryptedPrivateKey
Keys = new PublicKeyEncryptionKeyPairData(
wrappedPrivateKey: encryptedPrivateKey,
publicKey: publicKey)
};
// Act

View File

@@ -1,4 +1,4 @@
using Bit.Core.Enums;
using Bit.Core.Dirt.Enums;
using Xunit;
namespace Bit.Core.Test.Services;

View File

@@ -1,12 +1,15 @@
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.AdminConsole.Services.NoopImplementations;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Dirt.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Dirt.Services.NoopImplementations;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;
using Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Utilities;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
@@ -19,7 +22,7 @@ using StackExchange.Redis;
using Xunit;
using ZiggyCreatures.Caching.Fusion;
namespace Bit.Core.Test.AdminConsole.EventIntegrations;
namespace Bit.Core.Test.Dirt.EventIntegrations;
public class EventIntegrationServiceCollectionExtensionsTests
{

View File

@@ -1,9 +1,10 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Dirt.Services;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -11,7 +12,7 @@ using NSubstitute;
using Xunit;
using ZiggyCreatures.Caching.Fusion;
namespace Bit.Core.Test.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
namespace Bit.Core.Test.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
[SutProviderCustomize]
public class CreateOrganizationIntegrationConfigurationCommandTests

View File

@@ -1,8 +1,9 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -10,7 +11,7 @@ using NSubstitute;
using Xunit;
using ZiggyCreatures.Caching.Fusion;
namespace Bit.Core.Test.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
namespace Bit.Core.Test.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
[SutProviderCustomize]
public class DeleteOrganizationIntegrationConfigurationCommandTests

View File

@@ -1,13 +1,13 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
namespace Bit.Core.Test.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
[SutProviderCustomize]
public class GetOrganizationIntegrationConfigurationsQueryTests

View File

@@ -1,9 +1,10 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Dirt.Services;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -11,7 +12,7 @@ using NSubstitute;
using Xunit;
using ZiggyCreatures.Caching.Fusion;
namespace Bit.Core.Test.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
namespace Bit.Core.Test.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
[SutProviderCustomize]
public class UpdateOrganizationIntegrationConfigurationCommandTests

View File

@@ -1,8 +1,8 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations;
using Bit.Core.Enums;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -10,7 +10,7 @@ using NSubstitute;
using Xunit;
using ZiggyCreatures.Caching.Fusion;
namespace Bit.Core.Test.AdminConsole.EventIntegrations.OrganizationIntegrations;
namespace Bit.Core.Test.Dirt.EventIntegrations.OrganizationIntegrations;
[SutProviderCustomize]
public class CreateOrganizationIntegrationCommandTests

View File

@@ -1,8 +1,8 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations;
using Bit.Core.Enums;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -10,7 +10,7 @@ using NSubstitute;
using Xunit;
using ZiggyCreatures.Caching.Fusion;
namespace Bit.Core.Test.AdminConsole.EventIntegrations.OrganizationIntegrations;
namespace Bit.Core.Test.Dirt.EventIntegrations.OrganizationIntegrations;
[SutProviderCustomize]
public class DeleteOrganizationIntegrationCommandTests

View File

@@ -1,12 +1,12 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations;
using Bit.Core.Repositories;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
using Bit.Core.Dirt.Repositories;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.AdminConsole.EventIntegrations.OrganizationIntegrations;
namespace Bit.Core.Test.Dirt.EventIntegrations.OrganizationIntegrations;
[SutProviderCustomize]
public class GetOrganizationIntegrationsQueryTests

View File

@@ -1,8 +1,8 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations;
using Bit.Core.Enums;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -10,7 +10,7 @@ using NSubstitute;
using Xunit;
using ZiggyCreatures.Caching.Fusion;
namespace Bit.Core.Test.AdminConsole.EventIntegrations.OrganizationIntegrations;
namespace Bit.Core.Test.Dirt.EventIntegrations.OrganizationIntegrations;
[SutProviderCustomize]
public class UpdateOrganizationIntegrationCommandTests

View File

@@ -1,8 +1,8 @@
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;
namespace Bit.Core.Test.AdminConsole.Models.Data.EventIntegrations;
namespace Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
public class IntegrationHandlerResultTests
{

View File

@@ -1,9 +1,9 @@
using System.Text.Json;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Enums;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Xunit;
namespace Bit.Core.Test.Models.Data.EventIntegrations;
namespace Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
public class IntegrationMessageTests
{

View File

@@ -1,12 +1,12 @@
#nullable enable
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.Extensions.Time.Testing;
using Xunit;
namespace Bit.Core.Test.AdminConsole.Models.Data.EventIntegrations;
namespace Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
public class IntegrationOAuthStateTests
{

View File

@@ -1,13 +1,13 @@
#nullable enable
using System.Text.Json;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;
namespace Bit.Core.Test.AdminConsole.Models.Data.EventIntegrations;
namespace Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
public class IntegrationTemplateContextTests
{

View File

@@ -1,8 +1,8 @@
using System.Text.Json;
using Bit.Core.Models.Data.Organizations;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Xunit;
namespace Bit.Core.Test.Models.Data.Organizations;
namespace Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
public class OrganizationIntegrationConfigurationDetailsTests
{

View File

@@ -1,6 +1,7 @@
using Bit.Core.Enums;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
namespace Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
public class TestListenerConfiguration : IIntegrationListenerConfiguration
{

View File

@@ -1,8 +1,8 @@
using Bit.Core.AdminConsole.Models.Teams;
using Bit.Core.Dirt.Models.Data.Teams;
using Microsoft.Bot.Connector.Authentication;
using Xunit;
namespace Bit.Core.Test.Models.Data.Teams;
namespace Bit.Core.Test.Dirt.Models.Data.Teams;
public class TeamsBotCredentialProviderTests
{

View File

@@ -2,9 +2,10 @@
using System.Text.Json;
using Azure.Messaging.ServiceBus;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Models.Data;
using Bit.Core.Services;
using Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@@ -12,7 +13,7 @@ using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class AzureServiceBusEventListenerServiceTests

View File

@@ -2,8 +2,10 @@
using System.Text.Json;
using Azure.Messaging.ServiceBus;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Services;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.Extensions.Logging;
@@ -11,7 +13,7 @@ using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class AzureServiceBusIntegrationListenerServiceTests

View File

@@ -1,8 +1,8 @@
#nullable enable
using System.Net;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Services;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@@ -11,7 +11,7 @@ using Microsoft.Extensions.Time.Testing;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class DatadogIntegrationHandlerTests

View File

@@ -1,12 +1,13 @@
using System.Text.Json;
using Bit.Core.Dirt.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Models.Data;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class EventIntegrationEventWriteServiceTests

View File

@@ -2,14 +2,15 @@
using System.Text.Json;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Enums;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Dirt.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -19,7 +20,7 @@ using NSubstitute;
using Xunit;
using ZiggyCreatures.Caching.Fusion;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class EventIntegrationHandlerTests

View File

@@ -1,4 +1,5 @@
using Bit.Core.Models.Data;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Models.Data;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -6,7 +7,7 @@ using Bit.Test.Common.Helpers;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class EventRepositoryHandlerTests

View File

@@ -1,9 +1,9 @@
using Bit.Core.Models.Data;
using Bit.Core.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Models.Data;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
public class IntegrationFilterFactoryTests
{

View File

@@ -1,13 +1,13 @@
#nullable enable
using System.Text.Json;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Models.Data;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
public class IntegrationFilterServiceTests
{

View File

@@ -1,10 +1,10 @@
using System.Net;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Enums;
using Bit.Core.Services;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
public class IntegrationHandlerTests
{

View File

@@ -1,11 +1,11 @@
using System.Text.Json;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Enums;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services.Implementations;
using Xunit;
namespace Bit.Core.Test.AdminConsole.Services;
namespace Bit.Core.Test.Dirt.Services;
public class OrganizationIntegrationConfigurationValidatorTests
{

View File

@@ -1,9 +1,10 @@
#nullable enable
using System.Text.Json;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Models.Data;
using Bit.Core.Services;
using Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@@ -13,7 +14,7 @@ using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class RabbitMqEventListenerServiceTests

View File

@@ -1,8 +1,10 @@
#nullable enable
using System.Text;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Services;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Core.Test.Dirt.Models.Data.EventIntegrations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@@ -13,7 +15,7 @@ using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class RabbitMqIntegrationListenerServiceTests

View File

@@ -1,13 +1,14 @@
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Models.Slack;
using Bit.Core.Services;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Models.Data.Slack;
using Bit.Core.Dirt.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class SlackIntegrationHandlerTests

View File

@@ -3,7 +3,7 @@
using System.Net;
using System.Text.Json;
using System.Web;
using Bit.Core.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.MockedHttpClient;
@@ -11,7 +11,7 @@ using NSubstitute;
using Xunit;
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class SlackServiceTests

View File

@@ -1,6 +1,7 @@
using System.Text.Json;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Services;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@@ -9,7 +10,7 @@ using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class TeamsIntegrationHandlerTests

View File

@@ -3,11 +3,11 @@
using System.Net;
using System.Text.Json;
using System.Web;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Models.Teams;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Models.Data.Teams;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.MockedHttpClient;
@@ -15,7 +15,7 @@ using NSubstitute;
using Xunit;
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class TeamsServiceTests

View File

@@ -1,7 +1,7 @@
using System.Net;
using System.Net.Http.Headers;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Services;
using Bit.Core.Dirt.Models.Data.EventIntegrations;
using Bit.Core.Dirt.Services.Implementations;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@@ -10,7 +10,7 @@ using Microsoft.Extensions.Time.Testing;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Services;
namespace Bit.Core.Test.Dirt.Services;
[SutProviderCustomize]
public class WebhookIntegrationHandlerTests

View File

@@ -2,6 +2,7 @@
using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Exceptions;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.Models.Business;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions;
@@ -242,4 +243,134 @@ public class UpgradeOrganizationPlanCommandTests
await sutProvider.GetDependency<IOrganizationService>().DidNotReceiveWithAnyArgs().ReplaceAndUpdateCacheAsync(default);
}
[Theory]
[FreeOrganizationUpgradeCustomize, BitAutoData]
public async Task UpgradePlan_WhenOrganizationIsMissingPublicAndPrivateKeys_Backfills(
Organization organization,
OrganizationUpgrade upgrade,
string newPublicKey,
string newPrivateKey,
SutProvider<UpgradeOrganizationPlanCommand> sutProvider)
{
organization.PublicKey = null;
organization.PrivateKey = null;
upgrade.Plan = PlanType.TeamsAnnually;
upgrade.Keys = new PublicKeyEncryptionKeyPairData(
wrappedPrivateKey: newPrivateKey,
publicKey: newPublicKey);
upgrade.AdditionalSeats = 10;
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(organization.Id)
.Returns(organization);
sutProvider.GetDependency<IPricingClient>()
.GetPlanOrThrow(organization.PlanType)
.Returns(MockPlans.Get(organization.PlanType));
sutProvider.GetDependency<IPricingClient>()
.GetPlanOrThrow(upgrade.Plan)
.Returns(MockPlans.Get(upgrade.Plan));
sutProvider.GetDependency<IOrganizationRepository>()
.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id)
.Returns(new OrganizationSeatCounts { Sponsored = 0, Users = 1 });
// Act
await sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade);
// Assert
Assert.Equal(newPublicKey, organization.PublicKey);
Assert.Equal(newPrivateKey, organization.PrivateKey);
await sutProvider.GetDependency<IOrganizationService>()
.Received(1)
.ReplaceAndUpdateCacheAsync(organization);
}
[Theory]
[FreeOrganizationUpgradeCustomize, BitAutoData]
public async Task UpgradePlan_WhenOrganizationAlreadyHasPublicAndPrivateKeys_DoesNotOverwriteWithNull(
Organization organization,
OrganizationUpgrade upgrade,
SutProvider<UpgradeOrganizationPlanCommand> sutProvider)
{
// Arrange
const string existingPublicKey = "existing-public-key";
const string existingPrivateKey = "existing-private-key";
organization.PublicKey = existingPublicKey;
organization.PrivateKey = existingPrivateKey;
upgrade.Plan = PlanType.TeamsAnnually;
upgrade.Keys = null;
upgrade.AdditionalSeats = 10;
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(organization.Id)
.Returns(organization);
sutProvider.GetDependency<IPricingClient>()
.GetPlanOrThrow(organization.PlanType)
.Returns(MockPlans.Get(organization.PlanType));
sutProvider.GetDependency<IPricingClient>()
.GetPlanOrThrow(upgrade.Plan)
.Returns(MockPlans.Get(upgrade.Plan));
sutProvider.GetDependency<IOrganizationRepository>()
.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id)
.Returns(new OrganizationSeatCounts { Sponsored = 0, Users = 1 });
// Act
await sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade);
// Assert
Assert.Equal(existingPublicKey, organization.PublicKey);
Assert.Equal(existingPrivateKey, organization.PrivateKey);
await sutProvider.GetDependency<IOrganizationService>()
.Received(1)
.ReplaceAndUpdateCacheAsync(organization);
}
[Theory]
[FreeOrganizationUpgradeCustomize, BitAutoData]
public async Task UpgradePlan_WhenOrganizationAlreadyHasPublicAndPrivateKeys_DoesNotBackfillWithNewKeys(
Organization organization,
OrganizationUpgrade upgrade,
SutProvider<UpgradeOrganizationPlanCommand> sutProvider)
{
// Arrange
const string existingPublicKey = "existing-public-key";
const string existingPrivateKey = "existing-private-key";
const string newPublicKey = "new-public-key";
const string newPrivateKey = "new-private-key";
organization.PublicKey = existingPublicKey;
organization.PrivateKey = existingPrivateKey;
upgrade.Plan = PlanType.TeamsAnnually;
upgrade.Keys = new PublicKeyEncryptionKeyPairData(
wrappedPrivateKey: newPrivateKey,
publicKey: newPublicKey);
upgrade.AdditionalSeats = 10;
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(organization.Id)
.Returns(organization);
sutProvider.GetDependency<IPricingClient>()
.GetPlanOrThrow(organization.PlanType)
.Returns(MockPlans.Get(organization.PlanType));
sutProvider.GetDependency<IPricingClient>()
.GetPlanOrThrow(upgrade.Plan)
.Returns(MockPlans.Get(upgrade.Plan));
sutProvider.GetDependency<IOrganizationRepository>()
.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id)
.Returns(new OrganizationSeatCounts { Sponsored = 0, Users = 1 });
// Act
await sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade);
// Assert
Assert.Equal(existingPublicKey, organization.PublicKey);
Assert.Equal(existingPrivateKey, organization.PrivateKey);
await sutProvider.GetDependency<IOrganizationService>()
.Received(1)
.ReplaceAndUpdateCacheAsync(organization);
}
}

View File

@@ -25,11 +25,15 @@ using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
using Fido2NetLib;
using Fido2NetLib.Objects;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using NSubstitute;
using Xunit;
using static Fido2NetLib.Fido2;
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
namespace Bit.Core.Test.Services;
@@ -594,6 +598,209 @@ public class UserServiceTests
user.MasterPassword = null;
}
}
[Theory]
[BitAutoData(true)]
[BitAutoData(false)]
public async Task StartWebAuthnRegistrationAsync_BelowLimit_Succeeds(
bool hasPremium, SutProvider<UserService> sutProvider, User user)
{
// Arrange - Non-premium user with 4 credentials (below limit of 5)
SetupWebAuthnProvider(user, credentialCount: 4);
sutProvider.GetDependency<IGlobalSettings>().WebAuthn = new GlobalSettings.WebAuthnSettings
{
PremiumMaximumAllowedCredentials = 10,
NonPremiumMaximumAllowedCredentials = 5
};
user.Premium = hasPremium;
user.Id = Guid.NewGuid();
user.Email = "test@example.com";
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns(new List<OrganizationUser>());
var mockFido2 = sutProvider.GetDependency<IFido2>();
mockFido2.RequestNewCredential(
Arg.Any<Fido2User>(),
Arg.Any<List<PublicKeyCredentialDescriptor>>(),
Arg.Any<AuthenticatorSelection>(),
Arg.Any<AttestationConveyancePreference>())
.Returns(new CredentialCreateOptions
{
Challenge = new byte[] { 1, 2, 3 },
Rp = new PublicKeyCredentialRpEntity("example.com", "example.com", ""),
User = new Fido2User
{
Id = user.Id.ToByteArray(),
Name = user.Email,
DisplayName = user.Name
},
PubKeyCredParams = new List<PubKeyCredParam>()
});
// Act
var result = await sutProvider.Sut.StartWebAuthnRegistrationAsync(user);
// Assert
Assert.NotNull(result);
await sutProvider.GetDependency<IUserRepository>().Received(1).ReplaceAsync(user);
}
[Theory]
[BitAutoData(true)]
[BitAutoData(false)]
public async Task CompleteWebAuthRegistrationAsync_ExceedsLimit_ThrowsBadRequestException(bool hasPremium,
SutProvider<UserService> sutProvider, User user, AuthenticatorAttestationRawResponse deviceResponse)
{
// Arrange - time-of-check/time-of-use scenario: user now has 10 credentials (at limit)
SetupWebAuthnProviderWithPending(user, credentialCount: 10);
sutProvider.GetDependency<IGlobalSettings>().WebAuthn = new GlobalSettings.WebAuthnSettings
{
PremiumMaximumAllowedCredentials = 10,
NonPremiumMaximumAllowedCredentials = 5
};
user.Premium = hasPremium;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns(new List<OrganizationUser>());
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.CompleteWebAuthRegistrationAsync(user, 11, "NewKey", deviceResponse));
Assert.Equal("Maximum allowed WebAuthn credential count exceeded.", exception.Message);
}
[Theory]
[BitAutoData(true)]
[BitAutoData(false)]
public async Task CompleteWebAuthRegistrationAsync_BelowLimit_Succeeds(bool hasPremium,
SutProvider<UserService> sutProvider, User user, AuthenticatorAttestationRawResponse deviceResponse)
{
// Arrange - User has 4 credentials (below limit of 5)
SetupWebAuthnProviderWithPending(user, credentialCount: 4);
sutProvider.GetDependency<IGlobalSettings>().WebAuthn = new GlobalSettings.WebAuthnSettings
{
PremiumMaximumAllowedCredentials = 10,
NonPremiumMaximumAllowedCredentials = 5
};
user.Premium = hasPremium;
user.Id = Guid.NewGuid();
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns(new List<OrganizationUser>());
var mockFido2 = sutProvider.GetDependency<IFido2>();
mockFido2.MakeNewCredentialAsync(
Arg.Any<AuthenticatorAttestationRawResponse>(),
Arg.Any<CredentialCreateOptions>(),
Arg.Any<IsCredentialIdUniqueToUserAsyncDelegate>())
.Returns(new CredentialMakeResult("ok", "", new AttestationVerificationSuccess
{
Aaguid = Guid.NewGuid(),
Counter = 0,
CredentialId = new byte[] { 1, 2, 3 },
CredType = "public-key",
PublicKey = new byte[] { 4, 5, 6 },
Status = "ok",
User = new Fido2User
{
Id = user.Id.ToByteArray(),
Name = user.Email ?? "test@example.com",
DisplayName = user.Name ?? "Test User"
}
}));
// Act
var result = await sutProvider.Sut.CompleteWebAuthRegistrationAsync(user, 5, "NewKey", deviceResponse);
// Assert
Assert.True(result);
await sutProvider.GetDependency<IUserRepository>().Received(1).ReplaceAsync(user);
}
private static void SetupWebAuthnProvider(User user, int credentialCount)
{
var providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
var metadata = new Dictionary<string, object>();
// Add credentials as Key1, Key2, Key3, etc.
for (int i = 1; i <= credentialCount; i++)
{
metadata[$"Key{i}"] = new TwoFactorProvider.WebAuthnData
{
Name = $"Key {i}",
Descriptor = new PublicKeyCredentialDescriptor(new byte[] { (byte)i }),
PublicKey = new byte[] { (byte)i },
UserHandle = new byte[] { (byte)i },
SignatureCounter = 0,
CredType = "public-key",
RegDate = DateTime.UtcNow,
AaGuid = Guid.NewGuid()
};
}
providers[TwoFactorProviderType.WebAuthn] = new TwoFactorProvider
{
Enabled = true,
MetaData = metadata
};
user.SetTwoFactorProviders(providers);
}
private static void SetupWebAuthnProviderWithPending(User user, int credentialCount)
{
var providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
var metadata = new Dictionary<string, object>();
// Add existing credentials
for (int i = 1; i <= credentialCount; i++)
{
metadata[$"Key{i}"] = new TwoFactorProvider.WebAuthnData
{
Name = $"Key {i}",
Descriptor = new PublicKeyCredentialDescriptor(new byte[] { (byte)i }),
PublicKey = new byte[] { (byte)i },
UserHandle = new byte[] { (byte)i },
SignatureCounter = 0,
CredType = "public-key",
RegDate = DateTime.UtcNow,
AaGuid = Guid.NewGuid()
};
}
// Add pending registration
var pendingOptions = new CredentialCreateOptions
{
Challenge = new byte[] { 1, 2, 3 },
Rp = new PublicKeyCredentialRpEntity("example.com", "example.com", ""),
User = new Fido2User
{
Id = user.Id.ToByteArray(),
Name = user.Email ?? "test@example.com",
DisplayName = user.Name ?? "Test User"
},
PubKeyCredParams = new List<PubKeyCredParam>()
};
metadata["pending"] = pendingOptions.ToJson();
providers[TwoFactorProviderType.WebAuthn] = new TwoFactorProvider
{
Enabled = true,
MetaData = metadata
};
user.SetTwoFactorProviders(providers);
}
}
public static class UserServiceSutProviderExtensions

View File

@@ -0,0 +1,169 @@
using System.Security.Claims;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core.Tools.Entities;
using Bit.Core.Tools.Repositories;
using Bit.Core.Tools.SendFeatures.Queries;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Tools.Services;
public class SendOwnerQueryTests
{
private readonly ISendRepository _sendRepository;
private readonly IFeatureService _featureService;
private readonly IUserService _userService;
private readonly SendOwnerQuery _sendOwnerQuery;
private readonly Guid _currentUserId = Guid.NewGuid();
private readonly ClaimsPrincipal _user;
public SendOwnerQueryTests()
{
_sendRepository = Substitute.For<ISendRepository>();
_featureService = Substitute.For<IFeatureService>();
_userService = Substitute.For<IUserService>();
_user = new ClaimsPrincipal();
_userService.GetProperUserId(_user).Returns(_currentUserId);
_sendOwnerQuery = new SendOwnerQuery(_sendRepository, _featureService, _userService);
}
[Fact]
public async Task Get_WithValidSendOwnedByUser_ReturnsExpectedSend()
{
// Arrange
var sendId = Guid.NewGuid();
var expectedSend = CreateSend(sendId, _currentUserId);
_sendRepository.GetByIdAsync(sendId).Returns(expectedSend);
// Act
var result = await _sendOwnerQuery.Get(sendId, _user);
// Assert
Assert.Same(expectedSend, result);
await _sendRepository.Received(1).GetByIdAsync(sendId);
}
[Fact]
public async Task Get_WithNonExistentSend_ThrowsNotFoundException()
{
// Arrange
var sendId = Guid.NewGuid();
_sendRepository.GetByIdAsync(sendId).Returns((Send?)null);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() => _sendOwnerQuery.Get(sendId, _user));
}
[Fact]
public async Task Get_WithSendOwnedByDifferentUser_ThrowsNotFoundException()
{
// Arrange
var sendId = Guid.NewGuid();
var differentUserId = Guid.NewGuid();
var send = CreateSend(sendId, differentUserId);
_sendRepository.GetByIdAsync(sendId).Returns(send);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() => _sendOwnerQuery.Get(sendId, _user));
}
[Fact]
public async Task Get_WithNullCurrentUserId_ThrowsBadRequestException()
{
// Arrange
var sendId = Guid.NewGuid();
var send = CreateSend(sendId, _currentUserId);
_sendRepository.GetByIdAsync(sendId).Returns(send);
var nullUser = new ClaimsPrincipal();
_userService.GetProperUserId(nullUser).Returns((Guid?)null);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() => _sendOwnerQuery.Get(sendId, nullUser));
Assert.Equal("invalid user.", exception.Message);
}
[Fact]
public async Task GetOwned_WithFeatureFlagEnabled_ReturnsAllSends()
{
// Arrange
var sends = new List<Send>
{
CreateSend(Guid.NewGuid(), _currentUserId, emails: null),
CreateSend(Guid.NewGuid(), _currentUserId, emails: "test@example.com"),
CreateSend(Guid.NewGuid(), _currentUserId, emails: "other@example.com")
};
_sendRepository.GetManyByUserIdAsync(_currentUserId).Returns(sends);
_featureService.IsEnabled(FeatureFlagKeys.PM19051_ListEmailOtpSends).Returns(true);
// Act
var result = await _sendOwnerQuery.GetOwned(_user);
// Assert
Assert.Equal(3, result.Count);
Assert.Contains(sends[0], result);
Assert.Contains(sends[1], result);
Assert.Contains(sends[2], result);
await _sendRepository.Received(1).GetManyByUserIdAsync(_currentUserId);
_featureService.Received(1).IsEnabled(FeatureFlagKeys.PM19051_ListEmailOtpSends);
}
[Fact]
public async Task GetOwned_WithFeatureFlagDisabled_FiltersOutEmailOtpSends()
{
// Arrange
var sendWithoutEmails = CreateSend(Guid.NewGuid(), _currentUserId, emails: null);
var sendWithEmails = CreateSend(Guid.NewGuid(), _currentUserId, emails: "test@example.com");
var sends = new List<Send> { sendWithoutEmails, sendWithEmails };
_sendRepository.GetManyByUserIdAsync(_currentUserId).Returns(sends);
_featureService.IsEnabled(FeatureFlagKeys.PM19051_ListEmailOtpSends).Returns(false);
// Act
var result = await _sendOwnerQuery.GetOwned(_user);
// Assert
Assert.Single(result);
Assert.Contains(sendWithoutEmails, result);
Assert.DoesNotContain(sendWithEmails, result);
await _sendRepository.Received(1).GetManyByUserIdAsync(_currentUserId);
_featureService.Received(1).IsEnabled(FeatureFlagKeys.PM19051_ListEmailOtpSends);
}
[Fact]
public async Task GetOwned_WithNullCurrentUserId_ThrowsBadRequestException()
{
// Arrange
var nullUser = new ClaimsPrincipal();
_userService.GetProperUserId(nullUser).Returns((Guid?)null);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() => _sendOwnerQuery.GetOwned(nullUser));
Assert.Equal("invalid user.", exception.Message);
}
[Fact]
public async Task GetOwned_WithEmptyCollection_ReturnsEmptyCollection()
{
// Arrange
var emptySends = new List<Send>();
_sendRepository.GetManyByUserIdAsync(_currentUserId).Returns(emptySends);
_featureService.IsEnabled(FeatureFlagKeys.PM19051_ListEmailOtpSends).Returns(true);
// Act
var result = await _sendOwnerQuery.GetOwned(_user);
// Assert
Assert.Empty(result);
await _sendRepository.Received(1).GetManyByUserIdAsync(_currentUserId);
}
private static Send CreateSend(Guid id, Guid userId, string? emails = null)
{
return new Send
{
Id = id,
UserId = userId,
Emails = emails
};
}
}

View File

@@ -1,4 +1,5 @@
using Bit.Core.Enums;
using Bit.Core.Dirt.Enums;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;

View File

@@ -1190,6 +1190,7 @@ public class CipherServiceTests
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
.Returns(new Organization
{
UsePolicies = true,
PlanType = PlanType.EnterpriseAnnually,
MaxStorageGb = 100
});
@@ -1206,6 +1207,140 @@ public class CipherServiceTests
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
}
[Theory, BitAutoData]
public async Task ShareManyAsync_StorageLimitBypass_Passes(SutProvider<CipherService> sutProvider,
IEnumerable<CipherDetails> ciphers, Guid organizationId, List<Guid> collectionIds)
{
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
.Returns(new Organization
{
Id = organizationId,
PlanType = PlanType.EnterpriseAnnually,
UsePolicies = true,
MaxStorageGb = 3,
Storage = 3221225472 // 3 GB used, so 0 remaining
});
ciphers.FirstOrDefault().Attachments =
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
var cipherInfos = ciphers.Select(c => (c,
(DateTime?)c.RevisionDate));
var sharingUserId = ciphers.First().UserId.Value;
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.MigrateMyVaultToMyItems).Returns(true);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<OrganizationDataOwnershipPolicyRequirement>(sharingUserId)
.Returns(new OrganizationDataOwnershipPolicyRequirement(
OrganizationDataOwnershipState.Enabled,
[new PolicyDetails
{
OrganizationId = organizationId,
PolicyType = PolicyType.OrganizationDataOwnership,
OrganizationUserStatus = OrganizationUserStatusType.Confirmed,
}]));
await sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, sharingUserId);
await sutProvider.GetDependency<ICipherRepository>().Received(1).UpdateCiphersAsync(sharingUserId,
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
}
[Theory, BitAutoData]
public async Task ShareManyAsync_StorageLimit_Enforced(SutProvider<CipherService> sutProvider,
IEnumerable<CipherDetails> ciphers, Guid organizationId, List<Guid> collectionIds)
{
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
.Returns(new Organization
{
Id = organizationId,
PlanType = PlanType.EnterpriseAnnually,
UsePolicies = true,
MaxStorageGb = 3,
Storage = 3221225472 // 3 GB used, so 0 remaining
});
ciphers.FirstOrDefault().Attachments =
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
var cipherInfos = ciphers.Select(c => (c,
(DateTime?)c.RevisionDate));
var sharingUserId = ciphers.First().UserId.Value;
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<OrganizationDataOwnershipPolicyRequirement>(sharingUserId)
.Returns(new OrganizationDataOwnershipPolicyRequirement(OrganizationDataOwnershipState.Disabled, []));
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, sharingUserId)
);
Assert.Contains("Not enough storage available for this organization.", exception.Message);
await sutProvider.GetDependency<ICipherRepository>().DidNotReceive().UpdateCiphersAsync(sharingUserId,
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
}
[Theory, BitAutoData]
public async Task ShareManyAsync_StorageLimit_Enforced_WhenFeatureFlagDisabled(SutProvider<CipherService> sutProvider,
IEnumerable<CipherDetails> ciphers, Guid organizationId, List<Guid> collectionIds)
{
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
.Returns(new Organization
{
Id = organizationId,
PlanType = PlanType.EnterpriseAnnually,
UsePolicies = true,
MaxStorageGb = 3,
Storage = 3221225472 // 3 GB used, so 0 remaining
});
ciphers.FirstOrDefault().Attachments =
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
var cipherInfos = ciphers.Select(c => (c,
(DateTime?)c.RevisionDate));
var sharingUserId = ciphers.First().UserId.Value;
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.MigrateMyVaultToMyItems).Returns(false);
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, sharingUserId)
);
Assert.Contains("Not enough storage available for this organization.", exception.Message);
await sutProvider.GetDependency<ICipherRepository>().DidNotReceive().UpdateCiphersAsync(sharingUserId,
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
}
[Theory, BitAutoData]
public async Task ShareManyAsync_StorageLimit_Enforced_WhenUsePoliciesDisabled(SutProvider<CipherService> sutProvider,
IEnumerable<CipherDetails> ciphers, Guid organizationId, List<Guid> collectionIds)
{
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
.Returns(new Organization
{
Id = organizationId,
PlanType = PlanType.EnterpriseAnnually,
UsePolicies = false,
MaxStorageGb = 3,
Storage = 3221225472 // 3 GB used, so 0 remaining
});
ciphers.FirstOrDefault().Attachments =
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
var cipherInfos = ciphers.Select(c => (c,
(DateTime?)c.RevisionDate));
var sharingUserId = ciphers.First().UserId.Value;
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.MigrateMyVaultToMyItems).Returns(true);
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, sharingUserId)
);
Assert.Contains("Not enough storage available for this organization.", exception.Message);
await sutProvider.GetDependency<ICipherRepository>().DidNotReceive().UpdateCiphersAsync(sharingUserId,
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
}
private class SaveDetailsAsyncDependencies
{
public CipherDetails CipherDetails { get; set; }