mirror of
https://github.com/bitwarden/server.git
synced 2025-06-17 00:03:17 -05:00
Merge branch 'main' into user-service-test-tweaks
This commit is contained in:
commit
61390c0553
@ -3,7 +3,7 @@
|
|||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"tools": {
|
"tools": {
|
||||||
"swashbuckle.aspnetcore.cli": {
|
"swashbuckle.aspnetcore.cli": {
|
||||||
"version": "7.2.0",
|
"version": "7.3.2",
|
||||||
"commands": ["swagger"]
|
"commands": ["swagger"]
|
||||||
},
|
},
|
||||||
"dotnet-ef": {
|
"dotnet-ef": {
|
||||||
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -598,7 +598,7 @@ jobs:
|
|||||||
uses: bitwarden/gh-actions/.github/workflows/_ephemeral_environment_manager.yml@main
|
uses: bitwarden/gh-actions/.github/workflows/_ephemeral_environment_manager.yml@main
|
||||||
with:
|
with:
|
||||||
project: server
|
project: server
|
||||||
pull_request_number: ${{ github.event.number }}
|
pull_request_number: ${{ github.event.number || 0 }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
permissions: read-all
|
permissions: read-all
|
||||||
|
|
||||||
|
@ -550,6 +550,15 @@ public class ProviderBillingService(
|
|||||||
[
|
[
|
||||||
new CustomerTaxIdDataOptions { Type = taxIdType, Value = taxInfo.TaxIdNumber }
|
new CustomerTaxIdDataOptions { Type = taxIdType, Value = taxInfo.TaxIdNumber }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (taxIdType == StripeConstants.TaxIdType.SpanishNIF)
|
||||||
|
{
|
||||||
|
options.TaxIdData.Add(new CustomerTaxIdDataOptions
|
||||||
|
{
|
||||||
|
Type = StripeConstants.TaxIdType.EUVAT,
|
||||||
|
Value = $"ES{taxInfo.TaxIdNumber}"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(provider.DiscountId))
|
if (!string.IsNullOrEmpty(provider.DiscountId))
|
||||||
|
@ -11,7 +11,7 @@ $corsRules = (@{
|
|||||||
AllowedMethods = @("Get", "PUT");
|
AllowedMethods = @("Get", "PUT");
|
||||||
});
|
});
|
||||||
$containers = "attachments", "sendfiles", "misc";
|
$containers = "attachments", "sendfiles", "misc";
|
||||||
$queues = "event", "notifications", "reference-events", "mail";
|
$queues = "event", "notifications", "mail";
|
||||||
$tables = "event", "metadata", "installationdevice";
|
$tables = "event", "metadata", "installationdevice";
|
||||||
# End configuration
|
# End configuration
|
||||||
|
|
||||||
|
@ -242,10 +242,32 @@ public class OrganizationsController : Controller
|
|||||||
Seats = organization.Seats
|
Seats = organization.Seats
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (model.PlanType.HasValue)
|
||||||
|
{
|
||||||
|
var freePlan = await _pricingClient.GetPlanOrThrow(model.PlanType.Value);
|
||||||
|
var isDowngradingToFree = organization.PlanType != PlanType.Free && model.PlanType.Value == PlanType.Free;
|
||||||
|
if (isDowngradingToFree)
|
||||||
|
{
|
||||||
|
if (model.Seats.HasValue && model.Seats.Value > freePlan.PasswordManager.MaxSeats)
|
||||||
|
{
|
||||||
|
TempData["Error"] = $"Organizations with more than {freePlan.PasswordManager.MaxSeats} seats cannot be downgraded to the Free plan";
|
||||||
|
return RedirectToAction("Edit", new { id });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model.MaxCollections > freePlan.PasswordManager.MaxCollections)
|
||||||
|
{
|
||||||
|
TempData["Error"] = $"Organizations with more than {freePlan.PasswordManager.MaxCollections} collections cannot be downgraded to the Free plan. Your organization currently has {organization.MaxCollections} collections.";
|
||||||
|
return RedirectToAction("Edit", new { id });
|
||||||
|
}
|
||||||
|
|
||||||
|
model.MaxStorageGb = null;
|
||||||
|
model.ExpirationDate = null;
|
||||||
|
model.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpdateOrganization(organization, model);
|
UpdateOrganization(organization, model);
|
||||||
|
|
||||||
var plan = await _pricingClient.GetPlanOrThrow(organization.PlanType);
|
var plan = await _pricingClient.GetPlanOrThrow(organization.PlanType);
|
||||||
|
|
||||||
if (organization.UseSecretsManager && !plan.SupportsSecretsManager)
|
if (organization.UseSecretsManager && !plan.SupportsSecretsManager)
|
||||||
{
|
{
|
||||||
TempData["Error"] = "Plan does not support Secrets Manager";
|
TempData["Error"] = "Plan does not support Secrets Manager";
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="8.0.2" />
|
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="8.0.2" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="8.0.1" />
|
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="8.0.1" />
|
||||||
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.25.0" />
|
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.25.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.3.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -4,6 +4,7 @@ using Bit.Api.AdminConsole.Models.Request.Organizations;
|
|||||||
using Bit.Api.Billing.Models.Requests;
|
using Bit.Api.Billing.Models.Requests;
|
||||||
using Bit.Api.Billing.Models.Responses;
|
using Bit.Api.Billing.Models.Responses;
|
||||||
using Bit.Api.Billing.Queries.Organizations;
|
using Bit.Api.Billing.Queries.Organizations;
|
||||||
|
using Bit.Core.Billing.Enums;
|
||||||
using Bit.Core.Billing.Models;
|
using Bit.Core.Billing.Models;
|
||||||
using Bit.Core.Billing.Models.Sales;
|
using Bit.Core.Billing.Models.Sales;
|
||||||
using Bit.Core.Billing.Pricing;
|
using Bit.Core.Billing.Pricing;
|
||||||
@ -280,17 +281,36 @@ public class OrganizationBillingController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var organization = await organizationRepository.GetByIdAsync(organizationId);
|
var organization = await organizationRepository.GetByIdAsync(organizationId);
|
||||||
|
|
||||||
if (organization == null)
|
if (organization == null)
|
||||||
{
|
{
|
||||||
return Error.NotFound();
|
return Error.NotFound();
|
||||||
}
|
}
|
||||||
|
var existingPlan = organization.PlanType;
|
||||||
var organizationSignup = model.ToOrganizationSignup(user);
|
var organizationSignup = model.ToOrganizationSignup(user);
|
||||||
var sale = OrganizationSale.From(organization, organizationSignup);
|
var sale = OrganizationSale.From(organization, organizationSignup);
|
||||||
var plan = await pricingClient.GetPlanOrThrow(model.PlanType);
|
var plan = await pricingClient.GetPlanOrThrow(model.PlanType);
|
||||||
sale.Organization.PlanType = plan.Type;
|
sale.Organization.PlanType = plan.Type;
|
||||||
sale.Organization.Plan = plan.Name;
|
sale.Organization.Plan = plan.Name;
|
||||||
sale.SubscriptionSetup.SkipTrial = true;
|
sale.SubscriptionSetup.SkipTrial = true;
|
||||||
|
if (existingPlan == PlanType.Free && organization.GatewaySubscriptionId is not null)
|
||||||
|
{
|
||||||
|
sale.Organization.UseTotp = plan.HasTotp;
|
||||||
|
sale.Organization.UseGroups = plan.HasGroups;
|
||||||
|
sale.Organization.UseDirectory = plan.HasDirectory;
|
||||||
|
sale.Organization.SelfHost = plan.HasSelfHost;
|
||||||
|
sale.Organization.UsersGetPremium = plan.UsersGetPremium;
|
||||||
|
sale.Organization.UseEvents = plan.HasEvents;
|
||||||
|
sale.Organization.Use2fa = plan.Has2fa;
|
||||||
|
sale.Organization.UseApi = plan.HasApi;
|
||||||
|
sale.Organization.UsePolicies = plan.HasPolicies;
|
||||||
|
sale.Organization.UseSso = plan.HasSso;
|
||||||
|
sale.Organization.UseResetPassword = plan.HasResetPassword;
|
||||||
|
sale.Organization.UseKeyConnector = plan.HasKeyConnector;
|
||||||
|
sale.Organization.UseScim = plan.HasScim;
|
||||||
|
sale.Organization.UseCustomPermissions = plan.HasCustomPermissions;
|
||||||
|
sale.Organization.UseOrganizationDomains = plan.HasOrganizationDomains;
|
||||||
|
sale.Organization.MaxCollections = plan.PasswordManager.MaxCollections;
|
||||||
|
}
|
||||||
|
|
||||||
if (organizationSignup.PaymentMethodType == null || string.IsNullOrEmpty(organizationSignup.PaymentToken))
|
if (organizationSignup.PaymentMethodType == null || string.IsNullOrEmpty(organizationSignup.PaymentToken))
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@ using Bit.Core.Utilities;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Tools.Controllers;
|
namespace Bit.Api.Dirt.Controllers;
|
||||||
|
|
||||||
[Route("hibp")]
|
[Route("hibp")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
using Bit.Api.Tools.Models;
|
using Bit.Api.Dirt.Models;
|
||||||
using Bit.Api.Tools.Models.Response;
|
using Bit.Api.Dirt.Models.Response;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Dirt.Reports.Entities;
|
||||||
|
using Bit.Core.Dirt.Reports.Models.Data;
|
||||||
|
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||||
|
using Bit.Core.Dirt.Reports.ReportFeatures.OrganizationReportMembers.Interfaces;
|
||||||
|
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Tools.Entities;
|
|
||||||
using Bit.Core.Tools.Models.Data;
|
|
||||||
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
|
||||||
using Bit.Core.Tools.ReportFeatures.OrganizationReportMembers.Interfaces;
|
|
||||||
using Bit.Core.Tools.ReportFeatures.Requests;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Tools.Controllers;
|
namespace Bit.Api.Dirt.Controllers;
|
||||||
|
|
||||||
[Route("reports")]
|
[Route("reports")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
||||||
@ -47,7 +47,7 @@ public class ReportsController : Controller
|
|||||||
[HttpGet("member-cipher-details/{orgId}")]
|
[HttpGet("member-cipher-details/{orgId}")]
|
||||||
public async Task<IEnumerable<MemberCipherDetailsResponseModel>> GetMemberCipherDetails(Guid orgId)
|
public async Task<IEnumerable<MemberCipherDetailsResponseModel>> GetMemberCipherDetails(Guid orgId)
|
||||||
{
|
{
|
||||||
// Using the AccessReports permission here until new permissions
|
// Using the AccessReports permission here until new permissions
|
||||||
// are needed for more control over reports
|
// are needed for more control over reports
|
||||||
if (!await _currentContext.AccessReports(orgId))
|
if (!await _currentContext.AccessReports(orgId))
|
||||||
{
|
{
|
||||||
@ -84,7 +84,7 @@ public class ReportsController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the organization member info, the cipher ids associated with the member,
|
/// Contains the organization member info, the cipher ids associated with the member,
|
||||||
/// and details on their collections, groups, and permissions
|
/// and details on their collections, groups, and permissions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">Request to the MemberAccessCipherDetailsQuery</param>
|
/// <param name="request">Request to the MemberAccessCipherDetailsQuery</param>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Bit.Api.Tools.Models;
|
namespace Bit.Api.Dirt.Models;
|
||||||
|
|
||||||
public class PasswordHealthReportApplicationModel
|
public class PasswordHealthReportApplicationModel
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using Bit.Core.Tools.Models.Data;
|
using Bit.Core.Dirt.Reports.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Api.Tools.Models.Response;
|
namespace Bit.Api.Dirt.Models.Response;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the collections and group collections a user has access to including
|
/// Contains the collections and group collections a user has access to including
|
||||||
/// the permission level for the collection and group collection.
|
/// the permission level for the collection and group collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MemberAccessReportResponseModel
|
public class MemberAccessReportResponseModel
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Core.Tools.Models.Data;
|
using Bit.Core.Dirt.Reports.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Api.Tools.Models.Response;
|
namespace Bit.Api.Dirt.Models.Response;
|
||||||
|
|
||||||
public class MemberCipherDetailsResponseModel
|
public class MemberCipherDetailsResponseModel
|
||||||
{
|
{
|
||||||
|
@ -31,8 +31,8 @@ using Bit.Api.Billing;
|
|||||||
using Bit.Core.Auth.Models.Data;
|
using Bit.Core.Auth.Models.Data;
|
||||||
using Bit.Core.Auth.Identity.TokenProviders;
|
using Bit.Core.Auth.Identity.TokenProviders;
|
||||||
using Bit.Core.Tools.ImportFeatures;
|
using Bit.Core.Tools.ImportFeatures;
|
||||||
using Bit.Core.Tools.ReportFeatures;
|
|
||||||
using Bit.Core.Auth.Models.Api.Request;
|
using Bit.Core.Auth.Models.Api.Request;
|
||||||
|
using Bit.Core.Dirt.Reports.ReportFeatures;
|
||||||
using Bit.Core.Tools.SendFeatures;
|
using Bit.Core.Tools.SendFeatures;
|
||||||
|
|
||||||
#if !OSS
|
#if !OSS
|
||||||
|
@ -42,7 +42,6 @@ public class CiphersController : Controller
|
|||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
private readonly ILogger<CiphersController> _logger;
|
private readonly ILogger<CiphersController> _logger;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
private readonly IFeatureService _featureService;
|
|
||||||
private readonly IOrganizationCiphersQuery _organizationCiphersQuery;
|
private readonly IOrganizationCiphersQuery _organizationCiphersQuery;
|
||||||
private readonly IApplicationCacheService _applicationCacheService;
|
private readonly IApplicationCacheService _applicationCacheService;
|
||||||
private readonly ICollectionRepository _collectionRepository;
|
private readonly ICollectionRepository _collectionRepository;
|
||||||
@ -57,7 +56,6 @@ public class CiphersController : Controller
|
|||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
ILogger<CiphersController> logger,
|
ILogger<CiphersController> logger,
|
||||||
GlobalSettings globalSettings,
|
GlobalSettings globalSettings,
|
||||||
IFeatureService featureService,
|
|
||||||
IOrganizationCiphersQuery organizationCiphersQuery,
|
IOrganizationCiphersQuery organizationCiphersQuery,
|
||||||
IApplicationCacheService applicationCacheService,
|
IApplicationCacheService applicationCacheService,
|
||||||
ICollectionRepository collectionRepository)
|
ICollectionRepository collectionRepository)
|
||||||
@ -71,7 +69,6 @@ public class CiphersController : Controller
|
|||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
_featureService = featureService;
|
|
||||||
_organizationCiphersQuery = organizationCiphersQuery;
|
_organizationCiphersQuery = organizationCiphersQuery;
|
||||||
_applicationCacheService = applicationCacheService;
|
_applicationCacheService = applicationCacheService;
|
||||||
_collectionRepository = collectionRepository;
|
_collectionRepository = collectionRepository;
|
||||||
@ -375,11 +372,6 @@ public class CiphersController : Controller
|
|||||||
|
|
||||||
private async Task<bool> CanDeleteOrRestoreCipherAsAdminAsync(Guid organizationId, IEnumerable<Guid> cipherIds)
|
private async Task<bool> CanDeleteOrRestoreCipherAsAdminAsync(Guid organizationId, IEnumerable<Guid> cipherIds)
|
||||||
{
|
{
|
||||||
if (!_featureService.IsEnabled(FeatureFlagKeys.LimitItemDeletion))
|
|
||||||
{
|
|
||||||
return await CanEditCipherAsAdminAsync(organizationId, cipherIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
var org = _currentContext.GetOrganization(organizationId);
|
var org = _currentContext.GetOrganization(organizationId);
|
||||||
|
|
||||||
// If we're not an "admin" or if we're a provider user we don't need to check the ciphers
|
// If we're not an "admin" or if we're a provider user we don't need to check the ciphers
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Api.Vault.Models.Request;
|
using Bit.Api.Vault.Models.Request;
|
||||||
using Bit.Api.Vault.Models.Response;
|
using Bit.Api.Vault.Models.Response;
|
||||||
using Bit.Core;
|
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Bit.Core.Vault.Commands.Interfaces;
|
using Bit.Core.Vault.Commands.Interfaces;
|
||||||
using Bit.Core.Vault.Entities;
|
using Bit.Core.Vault.Entities;
|
||||||
using Bit.Core.Vault.Enums;
|
using Bit.Core.Vault.Enums;
|
||||||
@ -15,7 +13,6 @@ namespace Bit.Api.Vault.Controllers;
|
|||||||
|
|
||||||
[Route("tasks")]
|
[Route("tasks")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
||||||
[RequireFeature(FeatureFlagKeys.SecurityTasks)]
|
|
||||||
public class SecurityTaskController : Controller
|
public class SecurityTaskController : Controller
|
||||||
{
|
{
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.3.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -17,6 +17,7 @@ public enum PolicyType : byte
|
|||||||
AutomaticAppLogIn = 12,
|
AutomaticAppLogIn = 12,
|
||||||
FreeFamiliesSponsorshipPolicy = 13,
|
FreeFamiliesSponsorshipPolicy = 13,
|
||||||
RemoveUnlockWithPin = 14,
|
RemoveUnlockWithPin = 14,
|
||||||
|
RestrictedItemTypesPolicy = 15,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PolicyTypeExtensions
|
public static class PolicyTypeExtensions
|
||||||
@ -43,7 +44,8 @@ public static class PolicyTypeExtensions
|
|||||||
PolicyType.ActivateAutofill => "Active auto-fill",
|
PolicyType.ActivateAutofill => "Active auto-fill",
|
||||||
PolicyType.AutomaticAppLogIn => "Automatically log in users for allowed applications",
|
PolicyType.AutomaticAppLogIn => "Automatically log in users for allowed applications",
|
||||||
PolicyType.FreeFamiliesSponsorshipPolicy => "Remove Free Bitwarden Families sponsorship",
|
PolicyType.FreeFamiliesSponsorshipPolicy => "Remove Free Bitwarden Families sponsorship",
|
||||||
PolicyType.RemoveUnlockWithPin => "Remove unlock with PIN"
|
PolicyType.RemoveUnlockWithPin => "Remove unlock with PIN",
|
||||||
|
PolicyType.RestrictedItemTypesPolicy => "Restricted item types",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,12 @@ public static class StripeConstants
|
|||||||
public const string Reverse = "reverse";
|
public const string Reverse = "reverse";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TaxIdType
|
||||||
|
{
|
||||||
|
public const string EUVAT = "eu_vat";
|
||||||
|
public const string SpanishNIF = "es_cif";
|
||||||
|
}
|
||||||
|
|
||||||
public static class ValidateTaxLocationTiming
|
public static class ValidateTaxLocationTiming
|
||||||
{
|
{
|
||||||
public const string Deferred = "deferred";
|
public const string Deferred = "deferred";
|
||||||
|
@ -31,6 +31,7 @@ public record PlanAdapter : Plan
|
|||||||
HasScim = HasFeature("scim");
|
HasScim = HasFeature("scim");
|
||||||
HasResetPassword = HasFeature("resetPassword");
|
HasResetPassword = HasFeature("resetPassword");
|
||||||
UsersGetPremium = HasFeature("usersGetPremium");
|
UsersGetPremium = HasFeature("usersGetPremium");
|
||||||
|
HasCustomPermissions = HasFeature("customPermissions");
|
||||||
UpgradeSortOrder = plan.AdditionalData.TryGetValue("upgradeSortOrder", out var upgradeSortOrder)
|
UpgradeSortOrder = plan.AdditionalData.TryGetValue("upgradeSortOrder", out var upgradeSortOrder)
|
||||||
? int.Parse(upgradeSortOrder)
|
? int.Parse(upgradeSortOrder)
|
||||||
: 0;
|
: 0;
|
||||||
@ -141,6 +142,7 @@ public record PlanAdapter : Plan
|
|||||||
var stripeSeatPlanId = GetStripeSeatPlanId(seats);
|
var stripeSeatPlanId = GetStripeSeatPlanId(seats);
|
||||||
var hasAdditionalSeatsOption = seats.IsScalable;
|
var hasAdditionalSeatsOption = seats.IsScalable;
|
||||||
var seatPrice = GetSeatPrice(seats);
|
var seatPrice = GetSeatPrice(seats);
|
||||||
|
var baseSeats = GetBaseSeats(seats);
|
||||||
var maxSeats = GetMaxSeats(seats);
|
var maxSeats = GetMaxSeats(seats);
|
||||||
var allowSeatAutoscale = seats.IsScalable;
|
var allowSeatAutoscale = seats.IsScalable;
|
||||||
var maxProjects = plan.AdditionalData.TryGetValue("secretsManager.maxProjects", out var value) ? short.Parse(value) : 0;
|
var maxProjects = plan.AdditionalData.TryGetValue("secretsManager.maxProjects", out var value) ? short.Parse(value) : 0;
|
||||||
@ -156,6 +158,7 @@ public record PlanAdapter : Plan
|
|||||||
StripeSeatPlanId = stripeSeatPlanId,
|
StripeSeatPlanId = stripeSeatPlanId,
|
||||||
HasAdditionalSeatsOption = hasAdditionalSeatsOption,
|
HasAdditionalSeatsOption = hasAdditionalSeatsOption,
|
||||||
SeatPrice = seatPrice,
|
SeatPrice = seatPrice,
|
||||||
|
BaseSeats = baseSeats,
|
||||||
MaxSeats = maxSeats,
|
MaxSeats = maxSeats,
|
||||||
AllowSeatAutoscale = allowSeatAutoscale,
|
AllowSeatAutoscale = allowSeatAutoscale,
|
||||||
MaxProjects = maxProjects
|
MaxProjects = maxProjects
|
||||||
@ -168,8 +171,16 @@ public record PlanAdapter : Plan
|
|||||||
private static decimal GetBasePrice(PurchasableDTO purchasable)
|
private static decimal GetBasePrice(PurchasableDTO purchasable)
|
||||||
=> purchasable.FromPackaged(x => x.Price);
|
=> purchasable.FromPackaged(x => x.Price);
|
||||||
|
|
||||||
|
private static int GetBaseSeats(FreeOrScalableDTO freeOrScalable)
|
||||||
|
=> freeOrScalable.Match(
|
||||||
|
free => free.Quantity,
|
||||||
|
scalable => scalable.Provided);
|
||||||
|
|
||||||
private static int GetBaseSeats(PurchasableDTO purchasable)
|
private static int GetBaseSeats(PurchasableDTO purchasable)
|
||||||
=> purchasable.FromPackaged(x => x.Quantity);
|
=> purchasable.Match(
|
||||||
|
free => free.Quantity,
|
||||||
|
packaged => packaged.Quantity,
|
||||||
|
scalable => scalable.Provided);
|
||||||
|
|
||||||
private static short GetBaseServiceAccount(FreeOrScalableDTO freeOrScalable)
|
private static short GetBaseServiceAccount(FreeOrScalableDTO freeOrScalable)
|
||||||
=> freeOrScalable.Match(
|
=> freeOrScalable.Match(
|
||||||
|
@ -78,13 +78,14 @@ public class OrganizationBillingService(
|
|||||||
var isEligibleForSelfHost = await IsEligibleForSelfHostAsync(organization);
|
var isEligibleForSelfHost = await IsEligibleForSelfHostAsync(organization);
|
||||||
|
|
||||||
var isManaged = organization.Status == OrganizationStatusType.Managed;
|
var isManaged = organization.Status == OrganizationStatusType.Managed;
|
||||||
|
var orgOccupiedSeats = await organizationUserRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id);
|
||||||
if (string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
|
if (string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
|
||||||
{
|
{
|
||||||
return OrganizationMetadata.Default with
|
return OrganizationMetadata.Default with
|
||||||
{
|
{
|
||||||
IsEligibleForSelfHost = isEligibleForSelfHost,
|
IsEligibleForSelfHost = isEligibleForSelfHost,
|
||||||
IsManaged = isManaged
|
IsManaged = isManaged,
|
||||||
|
OrganizationOccupiedSeats = orgOccupiedSeats
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,8 +109,6 @@ public class OrganizationBillingService(
|
|||||||
? await stripeAdapter.InvoiceGetAsync(subscription.LatestInvoiceId, new InvoiceGetOptions())
|
? await stripeAdapter.InvoiceGetAsync(subscription.LatestInvoiceId, new InvoiceGetOptions())
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
var orgOccupiedSeats = await organizationUserRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id);
|
|
||||||
|
|
||||||
return new OrganizationMetadata(
|
return new OrganizationMetadata(
|
||||||
isEligibleForSelfHost,
|
isEligibleForSelfHost,
|
||||||
isManaged,
|
isManaged,
|
||||||
@ -248,12 +247,23 @@ public class OrganizationBillingService(
|
|||||||
organization.Id,
|
organization.Id,
|
||||||
customerSetup.TaxInformation.Country,
|
customerSetup.TaxInformation.Country,
|
||||||
customerSetup.TaxInformation.TaxId);
|
customerSetup.TaxInformation.TaxId);
|
||||||
|
|
||||||
|
throw new BadRequestException("billingTaxIdTypeInferenceError");
|
||||||
}
|
}
|
||||||
|
|
||||||
customerCreateOptions.TaxIdData =
|
customerCreateOptions.TaxIdData =
|
||||||
[
|
[
|
||||||
new() { Type = taxIdType, Value = customerSetup.TaxInformation.TaxId }
|
new() { Type = taxIdType, Value = customerSetup.TaxInformation.TaxId }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (taxIdType == StripeConstants.TaxIdType.SpanishNIF)
|
||||||
|
{
|
||||||
|
customerCreateOptions.TaxIdData.Add(new CustomerTaxIdDataOptions
|
||||||
|
{
|
||||||
|
Type = StripeConstants.TaxIdType.EUVAT,
|
||||||
|
Value = $"ES{customerSetup.TaxInformation.TaxId}"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (paymentMethodType, paymentMethodToken) = customerSetup.TokenizedPaymentSource;
|
var (paymentMethodType, paymentMethodToken) = customerSetup.TokenizedPaymentSource;
|
||||||
@ -420,7 +430,7 @@ public class OrganizationBillingService(
|
|||||||
var setNonUSBusinessUseToReverseCharge =
|
var setNonUSBusinessUseToReverseCharge =
|
||||||
featureService.IsEnabled(FeatureFlagKeys.PM21092_SetNonUSBusinessUseToReverseCharge);
|
featureService.IsEnabled(FeatureFlagKeys.PM21092_SetNonUSBusinessUseToReverseCharge);
|
||||||
|
|
||||||
if (setNonUSBusinessUseToReverseCharge)
|
if (setNonUSBusinessUseToReverseCharge && customer.HasBillingLocation())
|
||||||
{
|
{
|
||||||
subscriptionCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true };
|
subscriptionCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true };
|
||||||
}
|
}
|
||||||
|
@ -648,6 +648,12 @@ public class SubscriberService(
|
|||||||
{
|
{
|
||||||
await stripeAdapter.TaxIdCreateAsync(customer.Id,
|
await stripeAdapter.TaxIdCreateAsync(customer.Id,
|
||||||
new TaxIdCreateOptions { Type = taxIdType, Value = taxInformation.TaxId });
|
new TaxIdCreateOptions { Type = taxIdType, Value = taxInformation.TaxId });
|
||||||
|
|
||||||
|
if (taxIdType == StripeConstants.TaxIdType.SpanishNIF)
|
||||||
|
{
|
||||||
|
await stripeAdapter.TaxIdCreateAsync(customer.Id,
|
||||||
|
new TaxIdCreateOptions { Type = StripeConstants.TaxIdType.EUVAT, Value = $"ES{taxInformation.TaxId}" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (StripeException e)
|
catch (StripeException e)
|
||||||
{
|
{
|
||||||
|
@ -80,6 +80,15 @@ public class PreviewTaxAmountCommand(
|
|||||||
Value = taxInformation.TaxId
|
Value = taxInformation.TaxId
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (taxIdType == StripeConstants.TaxIdType.SpanishNIF)
|
||||||
|
{
|
||||||
|
options.CustomerDetails.TaxIds.Add(new InvoiceCustomerDetailsTaxIdOptions
|
||||||
|
{
|
||||||
|
Type = StripeConstants.TaxIdType.EUVAT,
|
||||||
|
Value = $"ES{parameters.TaxInformation.TaxId}"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (planType.GetProductTier() == ProductTierType.Families)
|
if (planType.GetProductTier() == ProductTierType.Families)
|
||||||
|
@ -181,6 +181,8 @@ public static class FeatureFlagKeys
|
|||||||
public const string EnablePMFlightRecorder = "enable-pm-flight-recorder";
|
public const string EnablePMFlightRecorder = "enable-pm-flight-recorder";
|
||||||
public const string MobileErrorReporting = "mobile-error-reporting";
|
public const string MobileErrorReporting = "mobile-error-reporting";
|
||||||
public const string AndroidChromeAutofill = "android-chrome-autofill";
|
public const string AndroidChromeAutofill = "android-chrome-autofill";
|
||||||
|
public const string EnablePMPreloginSettings = "enable-pm-prelogin-settings";
|
||||||
|
public const string AppIntents = "app-intents";
|
||||||
|
|
||||||
/* Platform Team */
|
/* Platform Team */
|
||||||
public const string PersistPopupView = "persist-popup-view";
|
public const string PersistPopupView = "persist-popup-view";
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using Bit.Core.Entities;
|
#nullable enable
|
||||||
|
|
||||||
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
#nullable enable
|
namespace Bit.Core.Dirt.Reports.Entities;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.Entities;
|
|
||||||
|
|
||||||
public class PasswordHealthReportApplication : ITableObject<Guid>, IRevisable
|
public class PasswordHealthReportApplication : ITableObject<Guid>, IRevisable
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Bit.Core.Tools.Models.Data;
|
namespace Bit.Core.Dirt.Reports.Models.Data;
|
||||||
|
|
||||||
public class MemberAccessDetails
|
public class MemberAccessDetails
|
||||||
{
|
{
|
||||||
@ -30,13 +30,13 @@ public class MemberAccessCipherDetails
|
|||||||
public bool UsesKeyConnector { get; set; }
|
public bool UsesKeyConnector { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The details for the member's collection access depending
|
/// The details for the member's collection access depending
|
||||||
/// on the collections and groups they are assigned to
|
/// on the collections and groups they are assigned to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<MemberAccessDetails> AccessDetails { get; set; }
|
public IEnumerable<MemberAccessDetails> AccessDetails { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A distinct list of the cipher ids associated with
|
/// A distinct list of the cipher ids associated with
|
||||||
/// the organization member
|
/// the organization member
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<string> CipherIds { get; set; }
|
public IEnumerable<string> CipherIds { get; set; }
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Dirt.Reports.Entities;
|
||||||
|
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||||
|
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
|
using Bit.Core.Dirt.Reports.Repositories;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Tools.Entities;
|
|
||||||
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
|
||||||
using Bit.Core.Tools.ReportFeatures.Requests;
|
|
||||||
using Bit.Core.Tools.Repositories;
|
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures;
|
||||||
|
|
||||||
public class AddPasswordHealthReportApplicationCommand : IAddPasswordHealthReportApplicationCommand
|
public class AddPasswordHealthReportApplicationCommand : IAddPasswordHealthReportApplicationCommand
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||||
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
using Bit.Core.Tools.ReportFeatures.Requests;
|
using Bit.Core.Dirt.Reports.Repositories;
|
||||||
using Bit.Core.Tools.Repositories;
|
using Bit.Core.Exceptions;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures;
|
||||||
|
|
||||||
public class DropPasswordHealthReportApplicationCommand : IDropPasswordHealthReportApplicationCommand
|
public class DropPasswordHealthReportApplicationCommand : IDropPasswordHealthReportApplicationCommand
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Dirt.Reports.Entities;
|
||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||||
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
using Bit.Core.Dirt.Reports.Repositories;
|
||||||
using Bit.Core.Tools.Repositories;
|
using Bit.Core.Exceptions;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures;
|
||||||
|
|
||||||
public class GetPasswordHealthReportApplicationQuery : IGetPasswordHealthReportApplicationQuery
|
public class GetPasswordHealthReportApplicationQuery : IGetPasswordHealthReportApplicationQuery
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Dirt.Reports.Entities;
|
||||||
using Bit.Core.Tools.ReportFeatures.Requests;
|
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures.Interfaces;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||||
|
|
||||||
public interface IAddPasswordHealthReportApplicationCommand
|
public interface IAddPasswordHealthReportApplicationCommand
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Core.Tools.ReportFeatures.Requests;
|
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures.Interfaces;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||||
|
|
||||||
public interface IDropPasswordHealthReportApplicationCommand
|
public interface IDropPasswordHealthReportApplicationCommand
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Dirt.Reports.Entities;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures.Interfaces;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||||
|
|
||||||
public interface IGetPasswordHealthReportApplicationQuery
|
public interface IGetPasswordHealthReportApplicationQuery
|
||||||
{
|
{
|
||||||
|
@ -2,21 +2,21 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
||||||
|
using Bit.Core.Dirt.Reports.Models.Data;
|
||||||
|
using Bit.Core.Dirt.Reports.ReportFeatures.OrganizationReportMembers.Interfaces;
|
||||||
|
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Data.Organizations;
|
using Bit.Core.Models.Data.Organizations;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Tools.Models.Data;
|
|
||||||
using Bit.Core.Tools.ReportFeatures.OrganizationReportMembers.Interfaces;
|
|
||||||
using Bit.Core.Tools.ReportFeatures.Requests;
|
|
||||||
using Bit.Core.Vault.Models.Data;
|
using Bit.Core.Vault.Models.Data;
|
||||||
using Bit.Core.Vault.Queries;
|
using Bit.Core.Vault.Queries;
|
||||||
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Requests;
|
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Requests;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures;
|
||||||
|
|
||||||
public class MemberAccessCipherDetailsQuery : IMemberAccessCipherDetailsQuery
|
public class MemberAccessCipherDetailsQuery : IMemberAccessCipherDetailsQuery
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using Bit.Core.Tools.Models.Data;
|
using Bit.Core.Dirt.Reports.Models.Data;
|
||||||
using Bit.Core.Tools.ReportFeatures.Requests;
|
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures.OrganizationReportMembers.Interfaces;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures.OrganizationReportMembers.Interfaces;
|
||||||
|
|
||||||
public interface IMemberAccessCipherDetailsQuery
|
public interface IMemberAccessCipherDetailsQuery
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||||
using Bit.Core.Tools.ReportFeatures.OrganizationReportMembers.Interfaces;
|
using Bit.Core.Dirt.Reports.ReportFeatures.OrganizationReportMembers.Interfaces;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures;
|
||||||
|
|
||||||
public static class ReportingServiceCollectionExtensions
|
public static class ReportingServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Bit.Core.Tools.ReportFeatures.Requests;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
|
|
||||||
public class AddPasswordHealthReportApplicationRequest
|
public class AddPasswordHealthReportApplicationRequest
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Bit.Core.Tools.ReportFeatures.Requests;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
|
|
||||||
public class DropPasswordHealthReportApplicationRequest
|
public class DropPasswordHealthReportApplicationRequest
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Bit.Core.Tools.ReportFeatures.Requests;
|
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||||
|
|
||||||
public class MemberAccessCipherDetailsRequest
|
public class MemberAccessCipherDetailsRequest
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using Bit.Core.Repositories;
|
using Bit.Core.Dirt.Reports.Entities;
|
||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Repositories;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.Repositories;
|
namespace Bit.Core.Dirt.Reports.Repositories;
|
||||||
|
|
||||||
public interface IPasswordHealthReportApplicationRepository : IRepository<PasswordHealthReportApplication, Guid>
|
public interface IPasswordHealthReportApplicationRepository : IRepository<PasswordHealthReportApplication, Guid>
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
@ -14,6 +15,8 @@ public class Collection : ITableObject<Guid>
|
|||||||
public string? ExternalId { get; set; }
|
public string? ExternalId { get; set; }
|
||||||
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
|
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
|
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
|
||||||
|
public CollectionType Type { get; set; } = CollectionType.SharedCollection;
|
||||||
|
public string? DefaultUserCollectionEmail { get; set; }
|
||||||
|
|
||||||
public void SetNewId()
|
public void SetNewId()
|
||||||
{
|
{
|
||||||
|
7
src/Core/Enums/CollectionType.cs
Normal file
7
src/Core/Enums/CollectionType.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Bit.Core.Enums;
|
||||||
|
|
||||||
|
public enum CollectionType
|
||||||
|
{
|
||||||
|
SharedCollection = 0,
|
||||||
|
DefaultUserCollection = 1,
|
||||||
|
}
|
@ -3,6 +3,8 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|||||||
|
|
||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class BadRequestException : Exception
|
public class BadRequestException : Exception
|
||||||
{
|
{
|
||||||
public BadRequestException() : base()
|
public BadRequestException() : base()
|
||||||
@ -41,5 +43,5 @@ public class BadRequestException : Exception
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModelStateDictionary ModelState { get; set; }
|
public ModelStateDictionary? ModelState { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class ConflictException : Exception
|
public class ConflictException : Exception
|
||||||
{
|
{
|
||||||
public ConflictException() : base("Conflict.") { }
|
public ConflictException() : base("Conflict.") { }
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class DnsQueryException : Exception
|
public class DnsQueryException : Exception
|
||||||
{
|
{
|
||||||
public DnsQueryException(string message)
|
public DnsQueryException(string message)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class DomainClaimedException : Exception
|
public class DomainClaimedException : Exception
|
||||||
{
|
{
|
||||||
public DomainClaimedException()
|
public DomainClaimedException()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class DomainVerifiedException : Exception
|
public class DomainVerifiedException : Exception
|
||||||
{
|
{
|
||||||
public DomainVerifiedException()
|
public DomainVerifiedException()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class DuplicateDomainException : Exception
|
public class DuplicateDomainException : Exception
|
||||||
{
|
{
|
||||||
public DuplicateDomainException()
|
public DuplicateDomainException()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Exception to throw when a requested feature is not yet enabled/available for the requesting context.
|
/// Exception to throw when a requested feature is not yet enabled/available for the requesting context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class GatewayException : Exception
|
public class GatewayException : Exception
|
||||||
{
|
{
|
||||||
public GatewayException(string message, Exception innerException = null)
|
public GatewayException(string message, Exception? innerException = null)
|
||||||
: base(message, innerException)
|
: base(message, innerException)
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class InvalidEmailException : Exception
|
public class InvalidEmailException : Exception
|
||||||
{
|
{
|
||||||
public InvalidEmailException()
|
public InvalidEmailException()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class InvalidGatewayCustomerIdException : Exception
|
public class InvalidGatewayCustomerIdException : Exception
|
||||||
{
|
{
|
||||||
public InvalidGatewayCustomerIdException()
|
public InvalidGatewayCustomerIdException()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.Exceptions;
|
namespace Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class NotFoundException : Exception
|
public class NotFoundException : Exception
|
||||||
{
|
{
|
||||||
public NotFoundException() : base()
|
public NotFoundException() : base()
|
||||||
|
@ -10,9 +10,11 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace Bit.Core.HostedServices;
|
namespace Bit.Core.HostedServices;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class ApplicationCacheHostedService : IHostedService, IDisposable
|
public class ApplicationCacheHostedService : IHostedService, IDisposable
|
||||||
{
|
{
|
||||||
private readonly InMemoryServiceBusApplicationCacheService _applicationCacheService;
|
private readonly InMemoryServiceBusApplicationCacheService? _applicationCacheService;
|
||||||
private readonly IOrganizationRepository _organizationRepository;
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
protected readonly ILogger<ApplicationCacheHostedService> _logger;
|
protected readonly ILogger<ApplicationCacheHostedService> _logger;
|
||||||
private readonly ServiceBusClient _serviceBusClient;
|
private readonly ServiceBusClient _serviceBusClient;
|
||||||
@ -20,8 +22,8 @@ public class ApplicationCacheHostedService : IHostedService, IDisposable
|
|||||||
private readonly ServiceBusAdministrationClient _serviceBusAdministrationClient;
|
private readonly ServiceBusAdministrationClient _serviceBusAdministrationClient;
|
||||||
private readonly string _subName;
|
private readonly string _subName;
|
||||||
private readonly string _topicName;
|
private readonly string _topicName;
|
||||||
private CancellationTokenSource _cts;
|
private CancellationTokenSource? _cts;
|
||||||
private Task _executingTask;
|
private Task? _executingTask;
|
||||||
|
|
||||||
|
|
||||||
public ApplicationCacheHostedService(
|
public ApplicationCacheHostedService(
|
||||||
@ -67,13 +69,17 @@ public class ApplicationCacheHostedService : IHostedService, IDisposable
|
|||||||
{
|
{
|
||||||
await _subscriptionReceiver.CloseAsync(cancellationToken);
|
await _subscriptionReceiver.CloseAsync(cancellationToken);
|
||||||
await _serviceBusClient.DisposeAsync();
|
await _serviceBusClient.DisposeAsync();
|
||||||
_cts.Cancel();
|
_cts?.Cancel();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _serviceBusAdministrationClient.DeleteSubscriptionAsync(_topicName, _subName, cancellationToken);
|
await _serviceBusAdministrationClient.DeleteSubscriptionAsync(_topicName, _subName, cancellationToken);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
await _executingTask;
|
|
||||||
|
if (_executingTask != null)
|
||||||
|
{
|
||||||
|
await _executingTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
|
@ -3,6 +3,8 @@ using Microsoft.Extensions.Hosting;
|
|||||||
|
|
||||||
namespace Bit.Core.HostedServices;
|
namespace Bit.Core.HostedServices;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A startup service that will seed the IP rate limiting stores with any values in the
|
/// A startup service that will seed the IP rate limiting stores with any values in the
|
||||||
/// GlobalSettings configuration.
|
/// GlobalSettings configuration.
|
||||||
|
@ -3,6 +3,8 @@ using Quartz;
|
|||||||
|
|
||||||
namespace Bit.Core.Jobs;
|
namespace Bit.Core.Jobs;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public abstract class BaseJob : IJob
|
public abstract class BaseJob : IJob
|
||||||
{
|
{
|
||||||
protected readonly ILogger _logger;
|
protected readonly ILogger _logger;
|
||||||
|
@ -8,6 +8,8 @@ using Quartz.Impl.Matchers;
|
|||||||
|
|
||||||
namespace Bit.Core.Jobs;
|
namespace Bit.Core.Jobs;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public abstract class BaseJobsHostedService : IHostedService, IDisposable
|
public abstract class BaseJobsHostedService : IHostedService, IDisposable
|
||||||
{
|
{
|
||||||
private const int MaximumJobRetries = 10;
|
private const int MaximumJobRetries = 10;
|
||||||
@ -16,7 +18,7 @@ public abstract class BaseJobsHostedService : IHostedService, IDisposable
|
|||||||
private readonly ILogger<JobListener> _listenerLogger;
|
private readonly ILogger<JobListener> _listenerLogger;
|
||||||
protected readonly ILogger _logger;
|
protected readonly ILogger _logger;
|
||||||
|
|
||||||
private IScheduler _scheduler;
|
private IScheduler? _scheduler;
|
||||||
protected GlobalSettings _globalSettings;
|
protected GlobalSettings _globalSettings;
|
||||||
|
|
||||||
public BaseJobsHostedService(
|
public BaseJobsHostedService(
|
||||||
@ -31,7 +33,7 @@ public abstract class BaseJobsHostedService : IHostedService, IDisposable
|
|||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Tuple<Type, ITrigger>> Jobs { get; protected set; }
|
public IEnumerable<Tuple<Type, ITrigger>>? Jobs { get; protected set; }
|
||||||
|
|
||||||
public virtual async Task StartAsync(CancellationToken cancellationToken)
|
public virtual async Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@ -61,10 +63,19 @@ public abstract class BaseJobsHostedService : IHostedService, IDisposable
|
|||||||
_scheduler.ListenerManager.AddJobListener(new JobListener(_listenerLogger),
|
_scheduler.ListenerManager.AddJobListener(new JobListener(_listenerLogger),
|
||||||
GroupMatcher<JobKey>.AnyGroup());
|
GroupMatcher<JobKey>.AnyGroup());
|
||||||
await _scheduler.Start(cancellationToken);
|
await _scheduler.Start(cancellationToken);
|
||||||
|
|
||||||
|
var jobKeys = new List<JobKey>();
|
||||||
|
var triggerKeys = new List<TriggerKey>();
|
||||||
|
|
||||||
if (Jobs != null)
|
if (Jobs != null)
|
||||||
{
|
{
|
||||||
foreach (var (job, trigger) in Jobs)
|
foreach (var (job, trigger) in Jobs)
|
||||||
{
|
{
|
||||||
|
jobKeys.Add(JobBuilder.Create(job)
|
||||||
|
.WithIdentity(job.FullName!)
|
||||||
|
.Build().Key);
|
||||||
|
triggerKeys.Add(trigger.Key);
|
||||||
|
|
||||||
for (var retry = 0; retry < MaximumJobRetries; retry++)
|
for (var retry = 0; retry < MaximumJobRetries; retry++)
|
||||||
{
|
{
|
||||||
// There's a race condition when starting multiple containers simultaneously, retry until it succeeds..
|
// There's a race condition when starting multiple containers simultaneously, retry until it succeeds..
|
||||||
@ -77,7 +88,7 @@ public abstract class BaseJobsHostedService : IHostedService, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
var jobDetail = JobBuilder.Create(job)
|
var jobDetail = JobBuilder.Create(job)
|
||||||
.WithIdentity(job.FullName)
|
.WithIdentity(job.FullName!)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var dupeJ = await _scheduler.GetJobDetail(jobDetail.Key);
|
var dupeJ = await _scheduler.GetJobDetail(jobDetail.Key);
|
||||||
@ -106,13 +117,6 @@ public abstract class BaseJobsHostedService : IHostedService, IDisposable
|
|||||||
|
|
||||||
// Delete old Jobs and Triggers
|
// Delete old Jobs and Triggers
|
||||||
var existingJobKeys = await _scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup());
|
var existingJobKeys = await _scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup());
|
||||||
var jobKeys = Jobs.Select(j =>
|
|
||||||
{
|
|
||||||
var job = j.Item1;
|
|
||||||
return JobBuilder.Create(job)
|
|
||||||
.WithIdentity(job.FullName)
|
|
||||||
.Build().Key;
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var key in existingJobKeys)
|
foreach (var key in existingJobKeys)
|
||||||
{
|
{
|
||||||
@ -126,7 +130,6 @@ public abstract class BaseJobsHostedService : IHostedService, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
var existingTriggerKeys = await _scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup());
|
var existingTriggerKeys = await _scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup());
|
||||||
var triggerKeys = Jobs.Select(j => j.Item2.Key);
|
|
||||||
|
|
||||||
foreach (var key in existingTriggerKeys)
|
foreach (var key in existingTriggerKeys)
|
||||||
{
|
{
|
||||||
@ -142,7 +145,10 @@ public abstract class BaseJobsHostedService : IHostedService, IDisposable
|
|||||||
|
|
||||||
public virtual async Task StopAsync(CancellationToken cancellationToken)
|
public virtual async Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await _scheduler?.Shutdown(cancellationToken);
|
if (_scheduler is not null)
|
||||||
|
{
|
||||||
|
await _scheduler.Shutdown(cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
|
@ -4,6 +4,8 @@ using Quartz.Spi;
|
|||||||
|
|
||||||
namespace Bit.Core.Jobs;
|
namespace Bit.Core.Jobs;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class JobFactory : IJobFactory
|
public class JobFactory : IJobFactory
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _container;
|
private readonly IServiceProvider _container;
|
||||||
@ -16,7 +18,7 @@ public class JobFactory : IJobFactory
|
|||||||
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
|
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
|
||||||
{
|
{
|
||||||
var scope = _container.CreateScope();
|
var scope = _container.CreateScope();
|
||||||
return scope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob;
|
return (scope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReturnJob(IJob job)
|
public void ReturnJob(IJob job)
|
||||||
|
@ -3,6 +3,8 @@ using Quartz;
|
|||||||
|
|
||||||
namespace Bit.Core.Jobs;
|
namespace Bit.Core.Jobs;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class JobListener : IJobListener
|
public class JobListener : IJobListener
|
||||||
{
|
{
|
||||||
private readonly ILogger<JobListener> _logger;
|
private readonly ILogger<JobListener> _logger;
|
||||||
@ -28,7 +30,7 @@ public class JobListener : IJobListener
|
|||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException,
|
public Task JobWasExecuted(IJobExecutionContext context, JobExecutionException? jobException,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
_logger.LogInformation(Constants.BypassFiltersEventId, null, "Finished job {0} at {1}.",
|
_logger.LogInformation(Constants.BypassFiltersEventId, null, "Finished job {0} at {1}.",
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Bit.Core.NotificationHub;
|
namespace Bit.Core.NotificationHub;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public interface INotificationHubProxy
|
public interface INotificationHubProxy
|
||||||
{
|
{
|
||||||
Task<(INotificationHubClient Client, NotificationOutcome Outcome)[]> SendTemplateNotificationAsync(IDictionary<string, string> properties, string tagExpression);
|
Task<(INotificationHubClient Client, NotificationOutcome Outcome)[]> SendTemplateNotificationAsync(IDictionary<string, string> properties, string tagExpression);
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Bit.Core.NotificationHub;
|
namespace Bit.Core.NotificationHub;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public interface INotificationHubPool
|
public interface INotificationHubPool
|
||||||
{
|
{
|
||||||
NotificationHubConnection ConnectionFor(Guid comb);
|
NotificationHubConnection ConnectionFor(Guid comb);
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Bit.Core.NotificationHub;
|
namespace Bit.Core.NotificationHub;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class NotificationHubClientProxy : INotificationHubProxy
|
public class NotificationHubClientProxy : INotificationHubProxy
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<INotificationHubClient> _clients;
|
private readonly IEnumerable<INotificationHubClient> _clients;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Security.Cryptography;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
@ -7,21 +8,23 @@ using Microsoft.Azure.NotificationHubs;
|
|||||||
|
|
||||||
namespace Bit.Core.NotificationHub;
|
namespace Bit.Core.NotificationHub;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class NotificationHubConnection
|
public class NotificationHubConnection
|
||||||
{
|
{
|
||||||
public string HubName { get; init; }
|
public string? HubName { get; init; }
|
||||||
public string ConnectionString { get; init; }
|
public string? ConnectionString { get; init; }
|
||||||
private Lazy<NotificationHubConnectionStringBuilder> _parsedConnectionString;
|
private Lazy<NotificationHubConnectionStringBuilder> _parsedConnectionString;
|
||||||
public Uri Endpoint => _parsedConnectionString.Value.Endpoint;
|
public Uri Endpoint => _parsedConnectionString.Value.Endpoint;
|
||||||
private string SasKey => _parsedConnectionString.Value.SharedAccessKey;
|
private string SasKey => _parsedConnectionString.Value.SharedAccessKey;
|
||||||
private string SasKeyName => _parsedConnectionString.Value.SharedAccessKeyName;
|
private string SasKeyName => _parsedConnectionString.Value.SharedAccessKeyName;
|
||||||
public bool EnableSendTracing { get; init; }
|
public bool EnableSendTracing { get; init; }
|
||||||
private NotificationHubClient _hubClient;
|
private NotificationHubClient? _hubClient;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the NotificationHubClient for this connection.
|
/// Gets the NotificationHubClient for this connection.
|
||||||
///
|
///
|
||||||
/// If the client is null, it will be initialized.
|
/// If the client is null, it will be initialized.
|
||||||
///
|
///
|
||||||
/// <throws>Exception</throws> if the connection is invalid.
|
/// <throws>Exception</throws> if the connection is invalid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NotificationHubClient HubClient
|
public NotificationHubClient HubClient
|
||||||
@ -45,13 +48,13 @@ public class NotificationHubConnection
|
|||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the start date for registration.
|
/// Gets the start date for registration.
|
||||||
///
|
///
|
||||||
/// If null, registration is always disabled.
|
/// If null, registration is always disabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime? RegistrationStartDate { get; init; }
|
public DateTime? RegistrationStartDate { get; init; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the end date for registration.
|
/// Gets the end date for registration.
|
||||||
///
|
///
|
||||||
/// If null, registration has no end date.
|
/// If null, registration has no end date.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime? RegistrationEndDate { get; init; }
|
public DateTime? RegistrationEndDate { get; init; }
|
||||||
@ -155,9 +158,10 @@ public class NotificationHubConnection
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_hubClient))]
|
||||||
private NotificationHubConnection Init()
|
private NotificationHubConnection Init()
|
||||||
{
|
{
|
||||||
HubClient = NotificationHubClient.CreateClientFromConnectionString(ConnectionString, HubName, EnableSendTracing);
|
_hubClient = NotificationHubClient.CreateClientFromConnectionString(ConnectionString, HubName, EnableSendTracing);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace Bit.Core.NotificationHub;
|
namespace Bit.Core.NotificationHub;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class NotificationHubPool : INotificationHubPool
|
public class NotificationHubPool : INotificationHubPool
|
||||||
{
|
{
|
||||||
private List<NotificationHubConnection> _connections { get; }
|
private List<NotificationHubConnection> _connections { get; }
|
||||||
|
@ -19,6 +19,8 @@ using Notification = Bit.Core.NotificationCenter.Entities.Notification;
|
|||||||
|
|
||||||
namespace Bit.Core.NotificationHub;
|
namespace Bit.Core.NotificationHub;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends mobile push notifications to the Azure Notification Hub.
|
/// Sends mobile push notifications to the Azure Notification Hub.
|
||||||
/// Used by Cloud-Hosted environments.
|
/// Used by Cloud-Hosted environments.
|
||||||
|
@ -13,6 +13,8 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace Bit.Core.NotificationHub;
|
namespace Bit.Core.NotificationHub;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public class NotificationHubPushRegistrationService : IPushRegistrationService
|
public class NotificationHubPushRegistrationService : IPushRegistrationService
|
||||||
{
|
{
|
||||||
private static readonly JsonSerializerOptions webPushSerializationOptions = new()
|
private static readonly JsonSerializerOptions webPushSerializationOptions = new()
|
||||||
@ -37,7 +39,7 @@ public class NotificationHubPushRegistrationService : IPushRegistrationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task CreateOrUpdateRegistrationAsync(PushRegistrationData data, string deviceId, string userId,
|
public async Task CreateOrUpdateRegistrationAsync(PushRegistrationData data, string deviceId, string userId,
|
||||||
string identifier, DeviceType type, IEnumerable<string> organizationIds, Guid installationId)
|
string? identifier, DeviceType type, IEnumerable<string> organizationIds, Guid installationId)
|
||||||
{
|
{
|
||||||
var orgIds = organizationIds.ToList();
|
var orgIds = organizationIds.ToList();
|
||||||
var clientType = DeviceTypes.ToClientType(type);
|
var clientType = DeviceTypes.ToClientType(type);
|
||||||
@ -79,7 +81,7 @@ public class NotificationHubPushRegistrationService : IPushRegistrationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task CreateOrUpdateMobileRegistrationAsync(Installation installation, string userId,
|
private async Task CreateOrUpdateMobileRegistrationAsync(Installation installation, string userId,
|
||||||
string identifier, ClientType clientType, List<string> organizationIds, DeviceType type, Guid installationId)
|
string? identifier, ClientType clientType, List<string> organizationIds, DeviceType type, Guid installationId)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(installation.PushChannel))
|
if (string.IsNullOrWhiteSpace(installation.PushChannel))
|
||||||
{
|
{
|
||||||
@ -137,7 +139,7 @@ public class NotificationHubPushRegistrationService : IPushRegistrationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task CreateOrUpdateWebRegistrationAsync(string endpoint, string p256dh, string auth, Installation installation, string userId,
|
private async Task CreateOrUpdateWebRegistrationAsync(string endpoint, string p256dh, string auth, Installation installation, string userId,
|
||||||
string identifier, ClientType clientType, List<string> organizationIds, Guid installationId)
|
string? identifier, ClientType clientType, List<string> organizationIds, Guid installationId)
|
||||||
{
|
{
|
||||||
// The Azure SDK is currently lacking support for web push registrations.
|
// The Azure SDK is currently lacking support for web push registrations.
|
||||||
// We need to use the REST API directly.
|
// We need to use the REST API directly.
|
||||||
@ -187,7 +189,7 @@ public class NotificationHubPushRegistrationService : IPushRegistrationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static KeyValuePair<string, InstallationTemplate> BuildInstallationTemplate(string templateId, [StringSyntax(StringSyntaxAttribute.Json)] string templateBody,
|
private static KeyValuePair<string, InstallationTemplate> BuildInstallationTemplate(string templateId, [StringSyntax(StringSyntaxAttribute.Json)] string templateBody,
|
||||||
string userId, string identifier, ClientType clientType, List<string> organizationIds, Guid installationId)
|
string userId, string? identifier, ClientType clientType, List<string> organizationIds, Guid installationId)
|
||||||
{
|
{
|
||||||
var fullTemplateId = $"template:{templateId}";
|
var fullTemplateId = $"template:{templateId}";
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
namespace Bit.Core.NotificationHub;
|
namespace Bit.Core.NotificationHub;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public record struct WebPushRegistrationData
|
public record struct WebPushRegistrationData
|
||||||
{
|
{
|
||||||
public string Endpoint { get; init; }
|
public string Endpoint { get; init; }
|
||||||
@ -9,9 +11,9 @@ public record struct WebPushRegistrationData
|
|||||||
|
|
||||||
public record class PushRegistrationData
|
public record class PushRegistrationData
|
||||||
{
|
{
|
||||||
public string Token { get; set; }
|
public string? Token { get; set; }
|
||||||
public WebPushRegistrationData? WebPush { get; set; }
|
public WebPushRegistrationData? WebPush { get; set; }
|
||||||
public PushRegistrationData(string token)
|
public PushRegistrationData(string? token)
|
||||||
{
|
{
|
||||||
Token = token;
|
Token = token;
|
||||||
}
|
}
|
||||||
|
@ -842,7 +842,13 @@ public class StripePaymentService : IPaymentService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _stripeAdapter.TaxIdCreateAsync(customer.Id,
|
await _stripeAdapter.TaxIdCreateAsync(customer.Id,
|
||||||
new TaxIdCreateOptions { Type = taxInfo.TaxIdType, Value = taxInfo.TaxIdNumber, });
|
new TaxIdCreateOptions { Type = taxInfo.TaxIdType, Value = taxInfo.TaxIdNumber });
|
||||||
|
|
||||||
|
if (taxInfo.TaxIdType == StripeConstants.TaxIdType.SpanishNIF)
|
||||||
|
{
|
||||||
|
await _stripeAdapter.TaxIdCreateAsync(customer.Id,
|
||||||
|
new TaxIdCreateOptions { Type = StripeConstants.TaxIdType.EUVAT, Value = $"ES{taxInfo.TaxIdNumber}" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (StripeException e)
|
catch (StripeException e)
|
||||||
{
|
{
|
||||||
@ -1000,6 +1006,15 @@ public class StripePaymentService : IPaymentService
|
|||||||
Value = parameters.TaxInformation.TaxId
|
Value = parameters.TaxInformation.TaxId
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (taxIdType == StripeConstants.TaxIdType.SpanishNIF)
|
||||||
|
{
|
||||||
|
options.CustomerDetails.TaxIds.Add(new InvoiceCustomerDetailsTaxIdOptions
|
||||||
|
{
|
||||||
|
Type = StripeConstants.TaxIdType.EUVAT,
|
||||||
|
Value = $"ES{parameters.TaxInformation.TaxId}"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(gatewayCustomerId))
|
if (!string.IsNullOrWhiteSpace(gatewayCustomerId))
|
||||||
@ -1154,6 +1169,15 @@ public class StripePaymentService : IPaymentService
|
|||||||
Value = parameters.TaxInformation.TaxId
|
Value = parameters.TaxInformation.TaxId
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (taxIdType == StripeConstants.TaxIdType.SpanishNIF)
|
||||||
|
{
|
||||||
|
options.CustomerDetails.TaxIds.Add(new InvoiceCustomerDetailsTaxIdOptions
|
||||||
|
{
|
||||||
|
Type = StripeConstants.TaxIdType.EUVAT,
|
||||||
|
Value = $"ES{parameters.TaxInformation.TaxId}"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Customer gatewayCustomer = null;
|
Customer gatewayCustomer = null;
|
||||||
|
@ -821,11 +821,6 @@ public class CipherService : ICipherService
|
|||||||
|
|
||||||
private async Task<bool> UserCanDeleteAsync(CipherDetails cipher, Guid userId)
|
private async Task<bool> UserCanDeleteAsync(CipherDetails cipher, Guid userId)
|
||||||
{
|
{
|
||||||
if (!_featureService.IsEnabled(FeatureFlagKeys.LimitItemDeletion))
|
|
||||||
{
|
|
||||||
return await UserCanEditAsync(cipher, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = await _userService.GetUserByIdAsync(userId);
|
var user = await _userService.GetUserByIdAsync(userId);
|
||||||
var organizationAbility = cipher.OrganizationId.HasValue ?
|
var organizationAbility = cipher.OrganizationId.HasValue ?
|
||||||
await _applicationCacheService.GetOrganizationAbilityAsync(cipher.OrganizationId.Value) : null;
|
await _applicationCacheService.GetOrganizationAbilityAsync(cipher.OrganizationId.Value) : null;
|
||||||
@ -835,11 +830,6 @@ public class CipherService : ICipherService
|
|||||||
|
|
||||||
private async Task<bool> UserCanRestoreAsync(CipherDetails cipher, Guid userId)
|
private async Task<bool> UserCanRestoreAsync(CipherDetails cipher, Guid userId)
|
||||||
{
|
{
|
||||||
if (!_featureService.IsEnabled(FeatureFlagKeys.LimitItemDeletion))
|
|
||||||
{
|
|
||||||
return await UserCanEditAsync(cipher, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = await _userService.GetUserByIdAsync(userId);
|
var user = await _userService.GetUserByIdAsync(userId);
|
||||||
var organizationAbility = cipher.OrganizationId.HasValue ?
|
var organizationAbility = cipher.OrganizationId.HasValue ?
|
||||||
await _applicationCacheService.GetOrganizationAbilityAsync(cipher.OrganizationId.Value) : null;
|
await _applicationCacheService.GetOrganizationAbilityAsync(cipher.OrganizationId.Value) : null;
|
||||||
@ -1059,17 +1049,11 @@ public class CipherService : ICipherService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This method is used to filter ciphers based on the user's permissions to delete them.
|
// This method is used to filter ciphers based on the user's permissions to delete them.
|
||||||
// It supports both the old and new logic depending on the feature flag.
|
|
||||||
private async Task<List<T>> FilterCiphersByDeletePermission<T>(
|
private async Task<List<T>> FilterCiphersByDeletePermission<T>(
|
||||||
IEnumerable<T> ciphers,
|
IEnumerable<T> ciphers,
|
||||||
HashSet<Guid> cipherIdsSet,
|
HashSet<Guid> cipherIdsSet,
|
||||||
Guid userId) where T : CipherDetails
|
Guid userId) where T : CipherDetails
|
||||||
{
|
{
|
||||||
if (!_featureService.IsEnabled(FeatureFlagKeys.LimitItemDeletion))
|
|
||||||
{
|
|
||||||
return ciphers.Where(c => cipherIdsSet.Contains(c.Id) && c.Edit).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = await _userService.GetUserByIdAsync(userId);
|
var user = await _userService.GetUserByIdAsync(userId);
|
||||||
var organizationAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
|
var organizationAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
|
||||||
|
|
||||||
|
@ -8,16 +8,6 @@ namespace Bit.Icons.Controllers;
|
|||||||
[Route("")]
|
[Route("")]
|
||||||
public class IconsController : Controller
|
public class IconsController : Controller
|
||||||
{
|
{
|
||||||
// Basic bwi-globe icon
|
|
||||||
private static readonly byte[] _notFoundImage = Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUg" +
|
|
||||||
"AAABMAAAATCAQAAADYWf5HAAABu0lEQVR42nXSvWuTURTH8R+t0heI9Y04aJycdBLNJNrBFBU7OFgUER3q21I0bXK+JwZ" +
|
|
||||||
"pXISm/QdcRB3EgqBBsNihsUbbgODQQSKCuKSDOApJuuhj8tCYQj/jvYfD795z1MZ+nBKrNKhSwrMxbZTrtRnqlEjZkB/x" +
|
|
||||||
"C/xmhZrlc71qS0Up8yVzTCGucFNKD1JhORVd70SZNU4okNx5d4+U2UXRIpJFWLClsR79YzN88wQvLWNzzPKEeS/wkQGpW" +
|
|
||||||
"VhhqhW8TtDJD3Mm1x/23zLSrZCdpBY8BueTNjHSbc+8wC9HlHgU5Aj5AW5zPdcVdpq0UcknWBSr/pjixO4gfp899Kd23p" +
|
|
||||||
"M2qQCH7LkCnqAqGh73OK/8NPOcaibr90LrW/yWAnaUhqjaOSl9nFR2r5rsqo22ypn1B5IN8VOUMHVgOnNQIX+d62plcz6" +
|
|
||||||
"rg1/jskK8CMb4we4pG6OWHtR/LBJkC2E4a7ZPkuX5ntumAOM2xxveclEhLvGH6XCmLPs735Eetrw63NnOgr9P9q1viC3x" +
|
|
||||||
"lRUGOjImqFDuOBvrYYoaZU9z1uPpYae5NfdvbNVG2ZjDIlXq/oMi46lo++4vjjPBl2Dlg00AAAAASUVORK5CYII=");
|
|
||||||
|
|
||||||
private readonly IMemoryCache _memoryCache;
|
private readonly IMemoryCache _memoryCache;
|
||||||
private readonly IDomainMappingService _domainMappingService;
|
private readonly IDomainMappingService _domainMappingService;
|
||||||
private readonly IIconFetchingService _iconFetchingService;
|
private readonly IIconFetchingService _iconFetchingService;
|
||||||
@ -99,7 +89,7 @@ public class IconsController : Controller
|
|||||||
|
|
||||||
if (icon == null)
|
if (icon == null)
|
||||||
{
|
{
|
||||||
return new FileContentResult(_notFoundImage, "image/png");
|
return new NotFoundResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FileContentResult(icon.Image, icon.Format);
|
return new FileContentResult(icon.Image, icon.Format);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Bit.Core.Auth.Repositories;
|
using Bit.Core.Auth.Repositories;
|
||||||
using Bit.Core.Billing.Providers.Repositories;
|
using Bit.Core.Billing.Providers.Repositories;
|
||||||
using Bit.Core.Billing.Repositories;
|
using Bit.Core.Billing.Repositories;
|
||||||
|
using Bit.Core.Dirt.Reports.Repositories;
|
||||||
using Bit.Core.KeyManagement.Repositories;
|
using Bit.Core.KeyManagement.Repositories;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
using Bit.Core.Platform.Installations;
|
using Bit.Core.Platform.Installations;
|
||||||
@ -12,6 +13,7 @@ using Bit.Core.Vault.Repositories;
|
|||||||
using Bit.Infrastructure.Dapper.AdminConsole.Repositories;
|
using Bit.Infrastructure.Dapper.AdminConsole.Repositories;
|
||||||
using Bit.Infrastructure.Dapper.Auth.Repositories;
|
using Bit.Infrastructure.Dapper.Auth.Repositories;
|
||||||
using Bit.Infrastructure.Dapper.Billing.Repositories;
|
using Bit.Infrastructure.Dapper.Billing.Repositories;
|
||||||
|
using Bit.Infrastructure.Dapper.Dirt;
|
||||||
using Bit.Infrastructure.Dapper.KeyManagement.Repositories;
|
using Bit.Infrastructure.Dapper.KeyManagement.Repositories;
|
||||||
using Bit.Infrastructure.Dapper.NotificationCenter.Repositories;
|
using Bit.Infrastructure.Dapper.NotificationCenter.Repositories;
|
||||||
using Bit.Infrastructure.Dapper.Platform;
|
using Bit.Infrastructure.Dapper.Platform;
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
|
using Bit.Core.Dirt.Reports.Entities;
|
||||||
|
using Bit.Core.Dirt.Reports.Repositories;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
using Bit.Core.Tools.Repositories;
|
|
||||||
using Bit.Infrastructure.Dapper.Repositories;
|
using Bit.Infrastructure.Dapper.Repositories;
|
||||||
using Dapper;
|
using Dapper;
|
||||||
using Microsoft.Data.SqlClient;
|
using Microsoft.Data.SqlClient;
|
||||||
using ToolsEntities = Bit.Core.Tools.Entities;
|
|
||||||
|
|
||||||
namespace Bit.Infrastructure.Dapper.Tools.Repositories;
|
namespace Bit.Infrastructure.Dapper.Dirt;
|
||||||
|
|
||||||
public class PasswordHealthReportApplicationRepository : Repository<ToolsEntities.PasswordHealthReportApplication, Guid>, IPasswordHealthReportApplicationRepository
|
public class PasswordHealthReportApplicationRepository : Repository<PasswordHealthReportApplication, Guid>, IPasswordHealthReportApplicationRepository
|
||||||
{
|
{
|
||||||
public PasswordHealthReportApplicationRepository(GlobalSettings globalSettings)
|
public PasswordHealthReportApplicationRepository(GlobalSettings globalSettings)
|
||||||
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
|
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
|
||||||
@ -18,11 +18,11 @@ public class PasswordHealthReportApplicationRepository : Repository<ToolsEntitie
|
|||||||
: base(connectionString, readOnlyConnectionString)
|
: base(connectionString, readOnlyConnectionString)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public async Task<ICollection<ToolsEntities.PasswordHealthReportApplication>> GetByOrganizationIdAsync(Guid organizationId)
|
public async Task<ICollection<PasswordHealthReportApplication>> GetByOrganizationIdAsync(Guid organizationId)
|
||||||
{
|
{
|
||||||
using (var connection = new SqlConnection(ReadOnlyConnectionString))
|
using (var connection = new SqlConnection(ReadOnlyConnectionString))
|
||||||
{
|
{
|
||||||
var results = await connection.QueryAsync<ToolsEntities.PasswordHealthReportApplication>(
|
var results = await connection.QueryAsync<PasswordHealthReportApplication>(
|
||||||
$"[{Schema}].[PasswordHealthReportApplication_ReadByOrganizationId]",
|
$"[{Schema}].[PasswordHealthReportApplication_ReadByOrganizationId]",
|
||||||
new { OrganizationId = organizationId },
|
new { OrganizationId = organizationId },
|
||||||
commandType: CommandType.StoredProcedure);
|
commandType: CommandType.StoredProcedure);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using Bit.Infrastructure.EntityFramework.Tools.Models;
|
using Bit.Infrastructure.EntityFramework.Dirt.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
namespace Bit.Infrastructure.EntityFramework.Tools.Configurations;
|
namespace Bit.Infrastructure.EntityFramework.Dirt.Configurations;
|
||||||
|
|
||||||
public class PasswordHealthReportApplicationEntityTypeConfiguration : IEntityTypeConfiguration<PasswordHealthReportApplication>
|
public class PasswordHealthReportApplicationEntityTypeConfiguration : IEntityTypeConfiguration<PasswordHealthReportApplication>
|
||||||
{
|
{
|
@ -1,9 +1,9 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Bit.Infrastructure.EntityFramework.AdminConsole.Models;
|
using Bit.Infrastructure.EntityFramework.AdminConsole.Models;
|
||||||
|
|
||||||
namespace Bit.Infrastructure.EntityFramework.Tools.Models;
|
namespace Bit.Infrastructure.EntityFramework.Dirt.Models;
|
||||||
|
|
||||||
public class PasswordHealthReportApplication : Core.Tools.Entities.PasswordHealthReportApplication
|
public class PasswordHealthReportApplication : Core.Dirt.Reports.Entities.PasswordHealthReportApplication
|
||||||
{
|
{
|
||||||
public virtual Organization Organization { get; set; }
|
public virtual Organization Organization { get; set; }
|
||||||
}
|
}
|
||||||
@ -12,7 +12,7 @@ public class PasswordHealthReportApplicationProfile : Profile
|
|||||||
{
|
{
|
||||||
public PasswordHealthReportApplicationProfile()
|
public PasswordHealthReportApplicationProfile()
|
||||||
{
|
{
|
||||||
CreateMap<Core.Tools.Entities.PasswordHealthReportApplication, PasswordHealthReportApplication>()
|
CreateMap<Core.Dirt.Reports.Entities.PasswordHealthReportApplication, PasswordHealthReportApplication>()
|
||||||
.ReverseMap();
|
.ReverseMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,22 +1,21 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Bit.Core.Tools.Repositories;
|
using Bit.Core.Dirt.Reports.Repositories;
|
||||||
|
using Bit.Infrastructure.EntityFramework.Dirt.Models;
|
||||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.Tools.Models;
|
|
||||||
using LinqToDB;
|
using LinqToDB;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using AdminConsoleEntities = Bit.Core.Tools.Entities;
|
|
||||||
|
|
||||||
namespace Bit.Infrastructure.EntityFramework.Tools.Repositories;
|
namespace Bit.Infrastructure.EntityFramework.Dirt.Repositories;
|
||||||
|
|
||||||
public class PasswordHealthReportApplicationRepository :
|
public class PasswordHealthReportApplicationRepository :
|
||||||
Repository<AdminConsoleEntities.PasswordHealthReportApplication, PasswordHealthReportApplication, Guid>,
|
Repository<Core.Dirt.Reports.Entities.PasswordHealthReportApplication, PasswordHealthReportApplication, Guid>,
|
||||||
IPasswordHealthReportApplicationRepository
|
IPasswordHealthReportApplicationRepository
|
||||||
{
|
{
|
||||||
public PasswordHealthReportApplicationRepository(IServiceScopeFactory serviceScopeFactory,
|
public PasswordHealthReportApplicationRepository(IServiceScopeFactory serviceScopeFactory,
|
||||||
IMapper mapper) : base(serviceScopeFactory, mapper, (DatabaseContext context) => context.PasswordHealthReportApplications)
|
IMapper mapper) : base(serviceScopeFactory, mapper, (DatabaseContext context) => context.PasswordHealthReportApplications)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public async Task<ICollection<AdminConsoleEntities.PasswordHealthReportApplication>> GetByOrganizationIdAsync(Guid organizationId)
|
public async Task<ICollection<Core.Dirt.Reports.Entities.PasswordHealthReportApplication>> GetByOrganizationIdAsync(Guid organizationId)
|
||||||
{
|
{
|
||||||
using (var scope = ServiceScopeFactory.CreateScope())
|
using (var scope = ServiceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
@ -24,7 +23,7 @@ public class PasswordHealthReportApplicationRepository :
|
|||||||
var results = await dbContext.PasswordHealthReportApplications
|
var results = await dbContext.PasswordHealthReportApplications
|
||||||
.Where(p => p.OrganizationId == organizationId)
|
.Where(p => p.OrganizationId == organizationId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
return Mapper.Map<ICollection<AdminConsoleEntities.PasswordHealthReportApplication>>(results);
|
return Mapper.Map<ICollection<Core.Dirt.Reports.Entities.PasswordHealthReportApplication>>(results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@
|
|||||||
using Bit.Core.Auth.Repositories;
|
using Bit.Core.Auth.Repositories;
|
||||||
using Bit.Core.Billing.Providers.Repositories;
|
using Bit.Core.Billing.Providers.Repositories;
|
||||||
using Bit.Core.Billing.Repositories;
|
using Bit.Core.Billing.Repositories;
|
||||||
|
using Bit.Core.Dirt.Reports.Repositories;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.KeyManagement.Repositories;
|
using Bit.Core.KeyManagement.Repositories;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
@ -13,6 +14,7 @@ using Bit.Core.Vault.Repositories;
|
|||||||
using Bit.Infrastructure.EntityFramework.AdminConsole.Repositories;
|
using Bit.Infrastructure.EntityFramework.AdminConsole.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.Auth.Repositories;
|
using Bit.Infrastructure.EntityFramework.Auth.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.Billing.Repositories;
|
using Bit.Infrastructure.EntityFramework.Billing.Repositories;
|
||||||
|
using Bit.Infrastructure.EntityFramework.Dirt.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.KeyManagement.Repositories;
|
using Bit.Infrastructure.EntityFramework.KeyManagement.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.NotificationCenter.Repositories;
|
using Bit.Infrastructure.EntityFramework.NotificationCenter.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.Platform;
|
using Bit.Infrastructure.EntityFramework.Platform;
|
||||||
|
@ -4,11 +4,11 @@ using Bit.Infrastructure.EntityFramework.AdminConsole.Models.Provider;
|
|||||||
using Bit.Infrastructure.EntityFramework.Auth.Models;
|
using Bit.Infrastructure.EntityFramework.Auth.Models;
|
||||||
using Bit.Infrastructure.EntityFramework.Billing.Models;
|
using Bit.Infrastructure.EntityFramework.Billing.Models;
|
||||||
using Bit.Infrastructure.EntityFramework.Converters;
|
using Bit.Infrastructure.EntityFramework.Converters;
|
||||||
|
using Bit.Infrastructure.EntityFramework.Dirt.Models;
|
||||||
using Bit.Infrastructure.EntityFramework.Models;
|
using Bit.Infrastructure.EntityFramework.Models;
|
||||||
using Bit.Infrastructure.EntityFramework.NotificationCenter.Models;
|
using Bit.Infrastructure.EntityFramework.NotificationCenter.Models;
|
||||||
using Bit.Infrastructure.EntityFramework.Platform;
|
using Bit.Infrastructure.EntityFramework.Platform;
|
||||||
using Bit.Infrastructure.EntityFramework.SecretsManager.Models;
|
using Bit.Infrastructure.EntityFramework.SecretsManager.Models;
|
||||||
using Bit.Infrastructure.EntityFramework.Tools.Models;
|
|
||||||
using Bit.Infrastructure.EntityFramework.Vault.Models;
|
using Bit.Infrastructure.EntityFramework.Vault.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.2.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.3.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -23,6 +23,7 @@ using Bit.Core.Auth.UserFeatures;
|
|||||||
using Bit.Core.Billing.Services;
|
using Bit.Core.Billing.Services;
|
||||||
using Bit.Core.Billing.Services.Implementations;
|
using Bit.Core.Billing.Services.Implementations;
|
||||||
using Bit.Core.Billing.TrialInitiation;
|
using Bit.Core.Billing.TrialInitiation;
|
||||||
|
using Bit.Core.Dirt.Reports.ReportFeatures;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.HostedServices;
|
using Bit.Core.HostedServices;
|
||||||
@ -43,7 +44,6 @@ using Bit.Core.Services;
|
|||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
using Bit.Core.Tokens;
|
using Bit.Core.Tokens;
|
||||||
using Bit.Core.Tools.ImportFeatures;
|
using Bit.Core.Tools.ImportFeatures;
|
||||||
using Bit.Core.Tools.ReportFeatures;
|
|
||||||
using Bit.Core.Tools.SendFeatures;
|
using Bit.Core.Tools.SendFeatures;
|
||||||
using Bit.Core.Tools.Services;
|
using Bit.Core.Tools.Services;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user