mirror of
https://github.com/bitwarden/server
synced 2026-01-14 06:23:46 +00:00
Merge remote-tracking branch 'origin' into auth/pm-22975/client-version-validator
This commit is contained in:
@@ -66,8 +66,8 @@ public class ProviderClientsControllerTests
|
||||
signup.Plan == requestBody.PlanType &&
|
||||
signup.AdditionalSeats == requestBody.Seats &&
|
||||
signup.OwnerKey == requestBody.Key &&
|
||||
signup.PublicKey == requestBody.KeyPair.PublicKey &&
|
||||
signup.PrivateKey == requestBody.KeyPair.EncryptedPrivateKey &&
|
||||
signup.Keys.PublicKey == requestBody.KeyPair.PublicKey &&
|
||||
signup.Keys.WrappedPrivateKey == requestBody.KeyPair.EncryptedPrivateKey &&
|
||||
signup.CollectionName == requestBody.CollectionName),
|
||||
requestBody.OwnerEmail,
|
||||
user)
|
||||
|
||||
@@ -85,6 +85,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
|
||||
user.Gateway = GatewayType.Stripe; // User has payment gateway
|
||||
|
||||
@@ -124,6 +125,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(false);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
|
||||
user.Gateway = GatewayType.Stripe; // User has payment gateway
|
||||
|
||||
@@ -161,6 +163,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
|
||||
user.Gateway = GatewayType.Stripe; // User has payment gateway
|
||||
|
||||
@@ -207,6 +210,7 @@ public class AccountsControllerTests : IDisposable
|
||||
};
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_userService.GenerateLicenseAsync(user).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
|
||||
// Act
|
||||
var result = await _sut.GetSubscriptionAsync(_globalSettings, _paymentService);
|
||||
@@ -243,6 +247,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
|
||||
user.Gateway = GatewayType.Stripe; // User has payment gateway
|
||||
|
||||
@@ -293,6 +298,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
|
||||
user.Gateway = GatewayType.Stripe;
|
||||
|
||||
@@ -349,6 +355,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
user.Gateway = GatewayType.Stripe;
|
||||
|
||||
// Act & Assert - Feature flag ENABLED
|
||||
@@ -413,6 +420,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
user.Gateway = GatewayType.Stripe;
|
||||
|
||||
// Act - Step 4: Call AccountsController.GetSubscriptionAsync
|
||||
@@ -507,6 +515,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
user.Gateway = GatewayType.Stripe;
|
||||
|
||||
// Act
|
||||
@@ -558,6 +567,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
user.Gateway = GatewayType.Stripe;
|
||||
|
||||
// Act
|
||||
@@ -611,6 +621,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
user.Gateway = GatewayType.Stripe;
|
||||
|
||||
// Act
|
||||
@@ -658,6 +669,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
user.Gateway = GatewayType.Stripe;
|
||||
|
||||
// Act
|
||||
@@ -726,6 +738,7 @@ public class AccountsControllerTests : IDisposable
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true);
|
||||
_paymentService.GetSubscriptionAsync(user).Returns(subscriptionInfo);
|
||||
_userService.GenerateLicenseAsync(user, subscriptionInfo).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
user.Gateway = GatewayType.Stripe;
|
||||
|
||||
// Act - Full pipeline: Stripe → SubscriptionInfo → SubscriptionResponseModel → API response
|
||||
@@ -791,6 +804,7 @@ public class AccountsControllerTests : IDisposable
|
||||
};
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_userService.GenerateLicenseAsync(user).Returns(license);
|
||||
_licensingService.GetClaimsPrincipalFromLicense(license).Returns(new ClaimsPrincipal());
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PM23341_Milestone_2).Returns(true); // Flag enabled
|
||||
|
||||
// Act
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
using Bit.Api.Billing.Controllers.VNext;
|
||||
using Bit.Core.Billing.Licenses.Queries;
|
||||
using Bit.Core.Billing.Payment.Commands;
|
||||
using Bit.Core.Billing.Payment.Queries;
|
||||
using Bit.Core.Billing.Premium.Commands;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Billing.Controllers.VNext;
|
||||
|
||||
public class AccountBillingVNextControllerTests
|
||||
{
|
||||
private readonly ICreateBitPayInvoiceForCreditCommand _createBitPayInvoiceForCreditCommand;
|
||||
private readonly ICreatePremiumCloudHostedSubscriptionCommand _createPremiumCloudHostedSubscriptionCommand;
|
||||
private readonly IGetCreditQuery _getCreditQuery;
|
||||
private readonly IGetPaymentMethodQuery _getPaymentMethodQuery;
|
||||
private readonly IGetUserLicenseQuery _getUserLicenseQuery;
|
||||
private readonly IUpdatePaymentMethodCommand _updatePaymentMethodCommand;
|
||||
private readonly AccountBillingVNextController _sut;
|
||||
|
||||
public AccountBillingVNextControllerTests()
|
||||
{
|
||||
_createBitPayInvoiceForCreditCommand = Substitute.For<ICreateBitPayInvoiceForCreditCommand>();
|
||||
_createPremiumCloudHostedSubscriptionCommand = Substitute.For<ICreatePremiumCloudHostedSubscriptionCommand>();
|
||||
_getCreditQuery = Substitute.For<IGetCreditQuery>();
|
||||
_getPaymentMethodQuery = Substitute.For<IGetPaymentMethodQuery>();
|
||||
_getUserLicenseQuery = Substitute.For<IGetUserLicenseQuery>();
|
||||
_updatePaymentMethodCommand = Substitute.For<IUpdatePaymentMethodCommand>();
|
||||
|
||||
_sut = new AccountBillingVNextController(
|
||||
_createBitPayInvoiceForCreditCommand,
|
||||
_createPremiumCloudHostedSubscriptionCommand,
|
||||
_getCreditQuery,
|
||||
_getPaymentMethodQuery,
|
||||
_getUserLicenseQuery,
|
||||
_updatePaymentMethodCommand);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetLicenseAsync_ValidUser_ReturnsLicenseResponse(User user,
|
||||
Core.Billing.Licenses.Models.Api.Response.LicenseResponseModel licenseResponse)
|
||||
{
|
||||
// Arrange
|
||||
_getUserLicenseQuery.Run(user).Returns(licenseResponse);
|
||||
|
||||
// Act
|
||||
var result = await _sut.GetLicenseAsync(user);
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsAssignableFrom<IResult>(result);
|
||||
await _getUserLicenseQuery.Received(1).Run(user);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using Bit.Api.AdminConsole.Controllers;
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Api.Dirt.Controllers;
|
||||
using Bit.Api.Dirt.Models.Request;
|
||||
using Bit.Api.Dirt.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
@@ -12,7 +12,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Controllers;
|
||||
namespace Bit.Api.Test.Dirt.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(OrganizationIntegrationController))]
|
||||
[SutProviderCustomize]
|
||||
@@ -1,9 +1,9 @@
|
||||
using Bit.Api.AdminConsole.Controllers;
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Api.Dirt.Controllers;
|
||||
using Bit.Api.Dirt.Models.Request;
|
||||
using Bit.Api.Dirt.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
@@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Controllers;
|
||||
namespace Bit.Api.Test.Dirt.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(OrganizationIntegrationConfigurationController))]
|
||||
[SutProviderCustomize]
|
||||
@@ -1,13 +1,13 @@
|
||||
#nullable enable
|
||||
|
||||
using Bit.Api.AdminConsole.Controllers;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Api.Dirt.Controllers;
|
||||
using Bit.Core.Context;
|
||||
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.Repositories;
|
||||
using Bit.Core.Dirt.Services;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -16,7 +16,7 @@ using Microsoft.Extensions.Time.Testing;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Controllers;
|
||||
namespace Bit.Api.Test.Dirt.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(SlackIntegrationController))]
|
||||
[SutProviderCustomize]
|
||||
@@ -1,14 +1,14 @@
|
||||
#nullable enable
|
||||
|
||||
using Bit.Api.AdminConsole.Controllers;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Api.Dirt.Controllers;
|
||||
using Bit.Core.Context;
|
||||
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.Models.Data.Teams;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Dirt.Services;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Teams;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@@ -20,7 +20,7 @@ using Microsoft.Extensions.Time.Testing;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Controllers;
|
||||
namespace Bit.Api.Test.Dirt.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(TeamsIntegrationController))]
|
||||
[SutProviderCustomize]
|
||||
@@ -1,13 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Api.Dirt.Models.Request;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Models.Request.Organizations;
|
||||
namespace Bit.Api.Test.Dirt.Models.Request;
|
||||
|
||||
public class OrganizationIntegrationRequestModelTests
|
||||
{
|
||||
@@ -1,15 +1,15 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Text.Json;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Teams;
|
||||
using Bit.Api.Dirt.Models.Response;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Dirt.Models.Data.Teams;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Models.Response.Organizations;
|
||||
namespace Bit.Api.Test.Dirt.Models.Response;
|
||||
|
||||
public class OrganizationIntegrationResponseModelTests
|
||||
{
|
||||
@@ -1,6 +1,9 @@
|
||||
using System.Text.Json;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Api.Tools.Controllers;
|
||||
using Bit.Api.Tools.Models;
|
||||
using Bit.Api.Tools.Models.Request;
|
||||
using Bit.Api.Tools.Models.Response;
|
||||
using Bit.Core.Entities;
|
||||
@@ -12,6 +15,7 @@ using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Data;
|
||||
using Bit.Core.Tools.Repositories;
|
||||
using Bit.Core.Tools.SendFeatures.Commands.Interfaces;
|
||||
using Bit.Core.Tools.SendFeatures.Queries.Interfaces;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -29,6 +33,7 @@ public class SendsControllerTests : IDisposable
|
||||
private readonly ISendRepository _sendRepository;
|
||||
private readonly INonAnonymousSendCommand _nonAnonymousSendCommand;
|
||||
private readonly IAnonymousSendCommand _anonymousSendCommand;
|
||||
private readonly ISendOwnerQuery _sendOwnerQuery;
|
||||
private readonly ISendAuthorizationService _sendAuthorizationService;
|
||||
private readonly ISendFileStorageService _sendFileStorageService;
|
||||
private readonly ILogger<SendsController> _logger;
|
||||
@@ -39,6 +44,7 @@ public class SendsControllerTests : IDisposable
|
||||
_sendRepository = Substitute.For<ISendRepository>();
|
||||
_nonAnonymousSendCommand = Substitute.For<INonAnonymousSendCommand>();
|
||||
_anonymousSendCommand = Substitute.For<IAnonymousSendCommand>();
|
||||
_sendOwnerQuery = Substitute.For<ISendOwnerQuery>();
|
||||
_sendAuthorizationService = Substitute.For<ISendAuthorizationService>();
|
||||
_sendFileStorageService = Substitute.For<ISendFileStorageService>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
@@ -50,6 +56,7 @@ public class SendsControllerTests : IDisposable
|
||||
_sendAuthorizationService,
|
||||
_anonymousSendCommand,
|
||||
_nonAnonymousSendCommand,
|
||||
_sendOwnerQuery,
|
||||
_sendFileStorageService,
|
||||
_logger,
|
||||
_globalSettings
|
||||
@@ -109,4 +116,641 @@ public class SendsControllerTests : IDisposable
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => _sut.PostFile(request));
|
||||
Assert.Equal(expected, exception.Message);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Get_WithValidId_ReturnsSendResponseModel(Guid sendId, Send send)
|
||||
{
|
||||
send.Type = SendType.Text;
|
||||
var textData = new SendTextData("Test Send", "Notes", "Sample text", false);
|
||||
send.Data = JsonSerializer.Serialize(textData);
|
||||
_sendOwnerQuery.Get(sendId, Arg.Any<ClaimsPrincipal>()).Returns(send);
|
||||
|
||||
var result = await _sut.Get(sendId.ToString());
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<SendResponseModel>(result);
|
||||
Assert.Equal(send.Id, result.Id);
|
||||
await _sendOwnerQuery.Received(1).Get(sendId, Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Get_WithInvalidGuid_ThrowsException(string invalidId)
|
||||
{
|
||||
await Assert.ThrowsAsync<FormatException>(() => _sut.Get(invalidId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAllOwned_ReturnsListResponseModelWithSendResponseModels()
|
||||
{
|
||||
var textSendData = new SendTextData("Test Send 1", "Notes 1", "Sample text", false);
|
||||
var fileSendData = new SendFileData("Test Send 2", "Notes 2", "test.txt") { Id = "file-123", Size = 1024 };
|
||||
var sends = new List<Send>
|
||||
{
|
||||
new Send { Id = Guid.NewGuid(), Type = SendType.Text, Data = JsonSerializer.Serialize(textSendData) },
|
||||
new Send { Id = Guid.NewGuid(), Type = SendType.File, Data = JsonSerializer.Serialize(fileSendData) }
|
||||
};
|
||||
_sendOwnerQuery.GetOwned(Arg.Any<ClaimsPrincipal>()).Returns(sends);
|
||||
|
||||
var result = await _sut.GetAll();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<ListResponseModel<SendResponseModel>>(result);
|
||||
Assert.Equal(2, result.Data.Count());
|
||||
var sendResponseModels = result.Data.ToList();
|
||||
Assert.Equal(sends[0].Id, sendResponseModels[0].Id);
|
||||
Assert.Equal(sends[1].Id, sendResponseModels[1].Id);
|
||||
await _sendOwnerQuery.Received(1).GetOwned(Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAllOwned_WhenNoSends_ReturnsEmptyListResponseModel()
|
||||
{
|
||||
_sendOwnerQuery.GetOwned(Arg.Any<ClaimsPrincipal>()).Returns(new List<Send>());
|
||||
|
||||
var result = await _sut.GetAll();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<ListResponseModel<SendResponseModel>>(result);
|
||||
Assert.Empty(result.Data);
|
||||
await _sendOwnerQuery.Received(1).GetOwned(Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Post_WithPassword_InfersAuthTypePassword(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
Password = "password",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Post(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(AuthType.Password, result.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.Password &&
|
||||
s.Password != null &&
|
||||
s.Emails == null &&
|
||||
s.UserId == userId &&
|
||||
s.Type == SendType.Text));
|
||||
_userService.Received(1).GetProperUserId(Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Post_WithEmails_InfersAuthTypeEmail(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
Emails = "test@example.com",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Post(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(AuthType.Email, result.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.Email &&
|
||||
s.Emails != null &&
|
||||
s.Password == null &&
|
||||
s.UserId == userId &&
|
||||
s.Type == SendType.Text));
|
||||
_userService.Received(1).GetProperUserId(Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Post_WithoutPasswordOrEmails_InfersAuthTypeNone(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Post(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(AuthType.None, result.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.None &&
|
||||
s.Password == null &&
|
||||
s.Emails == null &&
|
||||
s.UserId == userId &&
|
||||
s.Type == SendType.Text));
|
||||
_userService.Received(1).GetProperUserId(Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthType.Password)]
|
||||
[InlineData(AuthType.Email)]
|
||||
[InlineData(AuthType.None)]
|
||||
public async Task Access_ReturnsCorrectAuthType(AuthType authType)
|
||||
{
|
||||
var sendId = Guid.NewGuid();
|
||||
var accessId = CoreHelpers.Base64UrlEncode(sendId.ToByteArray());
|
||||
var send = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new Dictionary<string, string>()),
|
||||
AuthType = authType
|
||||
};
|
||||
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(send);
|
||||
_sendAuthorizationService.AccessAsync(send, "pwd123").Returns(SendAccessResult.Granted);
|
||||
|
||||
var request = new SendAccessRequestModel();
|
||||
var actionResult = await _sut.Access(accessId, request);
|
||||
var response = (actionResult as ObjectResult)?.Value as SendAccessResponseModel;
|
||||
|
||||
Assert.NotNull(response);
|
||||
Assert.Equal(authType, response.AuthType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthType.Password)]
|
||||
[InlineData(AuthType.Email)]
|
||||
[InlineData(AuthType.None)]
|
||||
public async Task Get_ReturnsCorrectAuthType(AuthType authType)
|
||||
{
|
||||
var sendId = Guid.NewGuid();
|
||||
var send = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("a", "b", "c", false)),
|
||||
AuthType = authType
|
||||
};
|
||||
|
||||
_sendOwnerQuery.Get(sendId, Arg.Any<ClaimsPrincipal>()).Returns(send);
|
||||
|
||||
var result = await _sut.Get(sendId.ToString());
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(authType, result.AuthType);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithValidSend_UpdatesSuccessfully(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
AuthType = AuthType.None
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
Password = "new-password",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s => s.Id == sendId));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithNonExistentSend_ThrowsNotFoundException(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_sendRepository.GetByIdAsync(sendId).Returns((Send)null);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.Put(sendId.ToString(), request));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithWrongUser_ThrowsNotFoundException(Guid userId, Guid otherUserId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = otherUserId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false))
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.Put(sendId.ToString(), request));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PutRemovePassword_WithValidSend_RemovesPasswordAndSetsAuthTypeNone(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Test", "Notes", "Text", false)),
|
||||
Password = "hashed-password",
|
||||
AuthType = AuthType.Password
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var result = await _sut.PutRemovePassword(sendId.ToString());
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
Assert.Equal(AuthType.None, result.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.Password == null &&
|
||||
s.AuthType == AuthType.None));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PutRemovePassword_WithNonExistentSend_ThrowsNotFoundException(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_sendRepository.GetByIdAsync(sendId).Returns((Send)null);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.PutRemovePassword(sendId.ToString()));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PutRemovePassword_WithWrongUser_ThrowsNotFoundException(Guid userId, Guid otherUserId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = otherUserId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Test", "Notes", "Text", false)),
|
||||
Password = "hashed-password"
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.PutRemovePassword(sendId.ToString()));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Delete_WithValidSend_DeletesSuccessfully(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Test", "Notes", "Text", false))
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
await _sut.Delete(sendId.ToString());
|
||||
|
||||
await _nonAnonymousSendCommand.Received(1).DeleteSendAsync(Arg.Is<Send>(s => s.Id == sendId));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Delete_WithNonExistentSend_ThrowsNotFoundException(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_sendRepository.GetByIdAsync(sendId).Returns((Send)null);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.Delete(sendId.ToString()));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Delete_WithWrongUser_ThrowsNotFoundException(Guid userId, Guid otherUserId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = otherUserId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Test", "Notes", "Text", false))
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.Delete(sendId.ToString()));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PostFile_WithPassword_InfersAuthTypePassword(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_nonAnonymousSendCommand.SaveFileSendAsync(Arg.Any<Send>(), Arg.Any<SendFileData>(), Arg.Any<long>())
|
||||
.Returns("https://example.com/upload")
|
||||
.AndDoes(callInfo =>
|
||||
{
|
||||
var send = callInfo.ArgAt<Send>(0);
|
||||
var data = callInfo.ArgAt<SendFileData>(1);
|
||||
send.Data = JsonSerializer.Serialize(data);
|
||||
});
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.File,
|
||||
Key = "key",
|
||||
File = new SendFileModel { FileName = "test.txt" },
|
||||
FileLength = 1024L,
|
||||
Password = "password",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.PostFile(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.SendResponse);
|
||||
Assert.Equal(AuthType.Password, result.SendResponse.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveFileSendAsync(
|
||||
Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.Password &&
|
||||
s.Password != null &&
|
||||
s.Emails == null &&
|
||||
s.UserId == userId),
|
||||
Arg.Any<SendFileData>(),
|
||||
1024L);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PostFile_WithEmails_InfersAuthTypeEmail(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_nonAnonymousSendCommand.SaveFileSendAsync(Arg.Any<Send>(), Arg.Any<SendFileData>(), Arg.Any<long>())
|
||||
.Returns("https://example.com/upload")
|
||||
.AndDoes(callInfo =>
|
||||
{
|
||||
var send = callInfo.ArgAt<Send>(0);
|
||||
var data = callInfo.ArgAt<SendFileData>(1);
|
||||
send.Data = JsonSerializer.Serialize(data);
|
||||
});
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.File,
|
||||
Key = "key",
|
||||
File = new SendFileModel { FileName = "test.txt" },
|
||||
FileLength = 1024L,
|
||||
Emails = "test@example.com",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.PostFile(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.SendResponse);
|
||||
Assert.Equal(AuthType.Email, result.SendResponse.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveFileSendAsync(
|
||||
Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.Email &&
|
||||
s.Emails != null &&
|
||||
s.Password == null &&
|
||||
s.UserId == userId),
|
||||
Arg.Any<SendFileData>(),
|
||||
1024L);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PostFile_WithoutPasswordOrEmails_InfersAuthTypeNone(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_nonAnonymousSendCommand.SaveFileSendAsync(Arg.Any<Send>(), Arg.Any<SendFileData>(), Arg.Any<long>())
|
||||
.Returns("https://example.com/upload")
|
||||
.AndDoes(callInfo =>
|
||||
{
|
||||
var send = callInfo.ArgAt<Send>(0);
|
||||
var data = callInfo.ArgAt<SendFileData>(1);
|
||||
send.Data = JsonSerializer.Serialize(data);
|
||||
});
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.File,
|
||||
Key = "key",
|
||||
File = new SendFileModel { FileName = "test.txt" },
|
||||
FileLength = 1024L,
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.PostFile(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.SendResponse);
|
||||
Assert.Equal(AuthType.None, result.SendResponse.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveFileSendAsync(
|
||||
Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.None &&
|
||||
s.Password == null &&
|
||||
s.Emails == null &&
|
||||
s.UserId == userId),
|
||||
Arg.Any<SendFileData>(),
|
||||
1024L);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_ChangingFromPasswordToEmails_UpdatesAuthTypeToEmail(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Password = "hashed-password",
|
||||
AuthType = AuthType.Password
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
Emails = "new@example.com",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.Email &&
|
||||
s.Emails != null &&
|
||||
s.Password == null));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_ChangingFromEmailToPassword_UpdatesAuthTypeToPassword(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Emails = "old@example.com",
|
||||
AuthType = AuthType.Email
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
Password = "new-password",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.Password &&
|
||||
s.Password != null &&
|
||||
s.Emails == null));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithoutPasswordOrEmails_PreservesExistingPassword(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Password = "hashed-password",
|
||||
AuthType = AuthType.Password
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.Password &&
|
||||
s.Password == "hashed-password" &&
|
||||
s.Emails == null));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithoutPasswordOrEmails_PreservesExistingEmails(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Emails = "test@example.com",
|
||||
AuthType = AuthType.Email
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.Email &&
|
||||
s.Emails == "test@example.com" &&
|
||||
s.Password == null));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithoutPasswordOrEmails_PreservesNoneAuthType(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Password = null,
|
||||
Emails = null,
|
||||
AuthType = AuthType.None
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.None &&
|
||||
s.Password == null &&
|
||||
s.Emails == null));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
169
test/Core.Test/Tools/Services/SendOwnerQueryTests.cs
Normal file
169
test/Core.Test/Tools/Services/SendOwnerQueryTests.cs
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -154,6 +154,7 @@ public abstract class WebApplicationFactoryBase<T> : WebApplicationFactory<T>
|
||||
|
||||
// Web push notifications
|
||||
{ "globalSettings:webPush:vapidPublicKey", "BGBtAM0bU3b5jsB14IjBYarvJZ6rWHilASLudTTYDDBi7a-3kebo24Yus_xYeOMZ863flAXhFAbkL6GVSrxgErg" },
|
||||
{ "globalSettings:launchDarkly:flagValues:web-push", "true" },
|
||||
};
|
||||
|
||||
// Some database drivers modify the connection string
|
||||
|
||||
Reference in New Issue
Block a user