diff --git a/src/Core/Services/Implementations/LicensingService.cs b/src/Core/Services/Implementations/LicensingService.cs index d32689aca..2ff14cbe4 100644 --- a/src/Core/Services/Implementations/LicensingService.cs +++ b/src/Core/Services/Implementations/LicensingService.cs @@ -62,25 +62,35 @@ namespace Bit.Core.Services return; } - var orgs = await _organizationRepository.GetManyByEnabledAsync(); - _logger.LogInformation("Validating licenses for {0} organizations.", orgs.Count); + var enabledOrgs = await _organizationRepository.GetManyByEnabledAsync(); + _logger.LogInformation("Validating licenses for {0} organizations.", enabledOrgs.Count); - foreach(var org in orgs) + foreach(var org in enabledOrgs) { var license = ReadOrganiztionLicense(org); - if(license == null || !license.VerifyData(org, _globalSettings) || !license.VerifySignature(_certificate)) + if(license == null) { - _logger.LogInformation("Organization {0}({1}) has an invalid license and is being disabled.", - org.Id, org.Name); + await DisableOrganizationAsync(org, null); + continue; + } - org.Enabled = false; - org.ExpirationDate = license.Expires; - org.RevisionDate = DateTime.UtcNow; - await _organizationRepository.ReplaceAsync(org); + var totalLicensedOrgs = enabledOrgs.Count(o => o.LicenseKey.Equals(license.LicenseKey)); + if(totalLicensedOrgs > 1 || !license.VerifyData(org, _globalSettings) || !license.VerifySignature(_certificate)) + { + await DisableOrganizationAsync(org, license); } } } + private async Task DisableOrganizationAsync(Organization org, ILicense license) + { + _logger.LogInformation("Organization {0}({1}) has an invalid license and is being disabled.", org.Id, org.Name); + org.Enabled = false; + org.ExpirationDate = license?.Expires ?? DateTime.UtcNow; + org.RevisionDate = DateTime.UtcNow; + await _organizationRepository.ReplaceAsync(org); + } + public async Task ValidateUsersAsync() { if(!_globalSettings.SelfHosted) @@ -178,7 +188,7 @@ namespace Bit.Core.Services user.Id, user.Email); user.Premium = false; - user.PremiumExpirationDate = license.Expires; + user.PremiumExpirationDate = license?.Expires ?? DateTime.UtcNow; user.RevisionDate = DateTime.UtcNow; await _userRepository.ReplaceAsync(user); } diff --git a/src/Core/Services/Implementations/OrganizationService.cs b/src/Core/Services/Implementations/OrganizationService.cs index ac313a231..a4b30da53 100644 --- a/src/Core/Services/Implementations/OrganizationService.cs +++ b/src/Core/Services/Implementations/OrganizationService.cs @@ -555,12 +555,18 @@ namespace Bit.Core.Services "hosting of organizations and that the installation id matches your current installation."); } - if(license.PlanType != PlanType.Custom && + if(license.PlanType != PlanType.Custom && StaticStore.Plans.FirstOrDefault(p => p.Type == license.PlanType && !p.Disabled) == null) { throw new BadRequestException("Plan not found."); } + var enabledOrgs = await _organizationRepository.GetManyByEnabledAsync(); + if(enabledOrgs.Any(o => o.LicenseKey.Equals(license.LicenseKey))) + { + throw new BadRequestException("License is already in use by another organization."); + } + var organization = new Organization { Name = license.Name, @@ -683,6 +689,12 @@ namespace Bit.Core.Services "hosting of organizations and that the installation id matches your current installation."); } + var enabledOrgs = await _organizationRepository.GetManyByEnabledAsync(); + if(enabledOrgs.Any(o => o.LicenseKey.Equals(license.LicenseKey) && o.Id != organizationId)) + { + throw new BadRequestException("License is already in use by another organization."); + } + if(license.Seats.HasValue && (!organization.Seats.HasValue || organization.Seats.Value > license.Seats.Value)) { var userCount = await _organizationUserRepository.GetCountByOrganizationIdAsync(organization.Id);