mirror of
https://github.com/bitwarden/server.git
synced 2025-02-16 01:51:21 +01:00
verify and disable premium from license check
This commit is contained in:
parent
cdc5310fc3
commit
b14f6d080e
@ -18,17 +18,20 @@ namespace Bit.Core.IdentityServer
|
||||
private readonly IUserService _userService;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly ILicensingService _licensingService;
|
||||
private IdentityOptions _identityOptions;
|
||||
|
||||
public ProfileService(
|
||||
IUserRepository userRepository,
|
||||
IUserService userService,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
ILicensingService licensingService,
|
||||
IOptions<IdentityOptions> identityOptionsAccessor)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
_userService = userService;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_licensingService = licensingService;
|
||||
_identityOptions = identityOptionsAccessor?.Value ?? new IdentityOptions();
|
||||
}
|
||||
|
||||
@ -40,9 +43,10 @@ namespace Bit.Core.IdentityServer
|
||||
var user = await _userService.GetUserByPrincipalAsync(context.Subject);
|
||||
if(user != null)
|
||||
{
|
||||
var isPremium = await _licensingService.VerifyUserPremiumAsync(user);
|
||||
newClaims.AddRange(new List<Claim>
|
||||
{
|
||||
new Claim("premium", user.Premium ? "true" : "false", ClaimValueTypes.Boolean),
|
||||
new Claim("premium", isPremium ? "true" : "false", ClaimValueTypes.Boolean),
|
||||
new Claim(JwtClaimTypes.Email, user.Email),
|
||||
new Claim(JwtClaimTypes.EmailVerified, user.EmailVerified ? "true" : "false", ClaimValueTypes.Boolean),
|
||||
new Claim(_identityOptions.ClaimsIdentity.SecurityStampClaimType, user.SecurityStamp)
|
||||
|
@ -167,7 +167,7 @@ namespace Bit.Core.Models.Business
|
||||
if(Version == 1)
|
||||
{
|
||||
return
|
||||
organization.LicenseKey.Equals(LicenseKey, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
organization.LicenseKey.Equals(LicenseKey) &&
|
||||
organization.Enabled == Enabled &&
|
||||
organization.PlanType == PlanType &&
|
||||
organization.Seats == Seats &&
|
||||
|
@ -116,7 +116,7 @@ namespace Bit.Core.Models.Business
|
||||
if(Version == 1)
|
||||
{
|
||||
return
|
||||
user.LicenseKey.Equals(LicenseKey, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
user.LicenseKey.Equals(LicenseKey) &&
|
||||
user.Premium == Premium &&
|
||||
user.Email.Equals(Email, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.Table;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public interface ILicensingService
|
||||
{
|
||||
bool VerifyOrganizationPlan(Organization organization);
|
||||
bool VerifyUserPremium(User user);
|
||||
Task<bool> VerifyUserPremiumAsync(User user);
|
||||
bool VerifyLicense(ILicense license);
|
||||
byte[] SignLicense(ILicense license);
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ namespace Bit.Core.Services
|
||||
Task CancelPremiumAsync(User user, bool endOfPeriod = false);
|
||||
Task ReinstatePremiumAsync(User user);
|
||||
Task DisablePremiumAsync(Guid userId, DateTime? expirationDate);
|
||||
Task DisablePremiumAsync(User user, DateTime? expirationDate);
|
||||
Task UpdatePremiumExpirationAsync(Guid userId, DateTime? expirationDate);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
@ -15,13 +16,17 @@ namespace Bit.Core.Services
|
||||
{
|
||||
private readonly X509Certificate2 _certificate;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private IDictionary<string, UserLicense> _userLicenseCache;
|
||||
private IDictionary<string, OrganizationLicense> _organizationLicenseCache;
|
||||
private IDictionary<Guid, DateTime> _userCheckCache = new Dictionary<Guid, DateTime>();
|
||||
private IDictionary<Guid, DateTime> _organizationCheckCache = new Dictionary<Guid, DateTime>();
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public RsaLicensingService(
|
||||
IUserService userService,
|
||||
IHostingEnvironment environment,
|
||||
GlobalSettings globalSettings)
|
||||
{
|
||||
_userService = userService;
|
||||
|
||||
var certThumbprint = "207e64a231e8aa32aaf68a61037c075ebebd553f";
|
||||
_globalSettings = globalSettings;
|
||||
_certificate = !_globalSettings.SelfHosted ? CoreHelpers.GetCertificate(certThumbprint)
|
||||
@ -54,7 +59,7 @@ namespace Bit.Core.Services
|
||||
return license != null && license.VerifyData(organization) && license.VerifySignature(_certificate);
|
||||
}
|
||||
|
||||
public bool VerifyUserPremium(User user)
|
||||
public async Task<bool> VerifyUserPremiumAsync(User user)
|
||||
{
|
||||
if(!_globalSettings.SelfHosted)
|
||||
{
|
||||
@ -66,8 +71,33 @@ namespace Bit.Core.Services
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only check once per day
|
||||
var now = DateTime.UtcNow;
|
||||
if(_userCheckCache.ContainsKey(user.Id))
|
||||
{
|
||||
var lastCheck = _userCheckCache[user.Id];
|
||||
if(lastCheck < now && now - lastCheck < TimeSpan.FromDays(1))
|
||||
{
|
||||
return user.Premium;
|
||||
}
|
||||
else
|
||||
{
|
||||
_userCheckCache[user.Id] = now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_userCheckCache.Add(user.Id, now);
|
||||
}
|
||||
|
||||
var license = ReadUserLicense(user);
|
||||
return license != null && license.VerifyData(user) && license.VerifySignature(_certificate);
|
||||
var licensedForPremium = license != null && license.VerifyData(user) && license.VerifySignature(_certificate);
|
||||
if(!licensedForPremium)
|
||||
{
|
||||
await _userService.DisablePremiumAsync(user, license.Expires);
|
||||
}
|
||||
|
||||
return licensedForPremium;
|
||||
}
|
||||
|
||||
public bool VerifyLicense(ILicense license)
|
||||
@ -87,11 +117,6 @@ namespace Bit.Core.Services
|
||||
|
||||
private UserLicense ReadUserLicense(User user)
|
||||
{
|
||||
if(_userLicenseCache != null && _userLicenseCache.ContainsKey(user.LicenseKey))
|
||||
{
|
||||
return _userLicenseCache[user.LicenseKey];
|
||||
}
|
||||
|
||||
var filePath = $"{_globalSettings.LicenseDirectory}/user/{user.Id}.json";
|
||||
if(!File.Exists(filePath))
|
||||
{
|
||||
@ -99,22 +124,11 @@ namespace Bit.Core.Services
|
||||
}
|
||||
|
||||
var data = File.ReadAllText(filePath, Encoding.UTF8);
|
||||
var obj = JsonConvert.DeserializeObject<UserLicense>(data);
|
||||
if(_userLicenseCache == null)
|
||||
{
|
||||
_userLicenseCache = new Dictionary<string, UserLicense>();
|
||||
}
|
||||
_userLicenseCache.Add(obj.LicenseKey, obj);
|
||||
return obj;
|
||||
return JsonConvert.DeserializeObject<UserLicense>(data);
|
||||
}
|
||||
|
||||
private OrganizationLicense ReadOrganiztionLicense(Organization organization)
|
||||
{
|
||||
if(_organizationLicenseCache != null && _organizationLicenseCache.ContainsKey(organization.LicenseKey))
|
||||
{
|
||||
return _organizationLicenseCache[organization.LicenseKey];
|
||||
}
|
||||
|
||||
var filePath = $"{_globalSettings.LicenseDirectory}/organization/{organization.Id}.json";
|
||||
if(!File.Exists(filePath))
|
||||
{
|
||||
@ -122,13 +136,7 @@ namespace Bit.Core.Services
|
||||
}
|
||||
|
||||
var data = File.ReadAllText(filePath, Encoding.UTF8);
|
||||
var obj = JsonConvert.DeserializeObject<OrganizationLicense>(data);
|
||||
if(_organizationLicenseCache == null)
|
||||
{
|
||||
_organizationLicenseCache = new Dictionary<string, OrganizationLicense>();
|
||||
}
|
||||
_organizationLicenseCache.Add(obj.LicenseKey, obj);
|
||||
return obj;
|
||||
return JsonConvert.DeserializeObject<OrganizationLicense>(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -691,6 +691,11 @@ namespace Bit.Core.Services
|
||||
public async Task DisablePremiumAsync(Guid userId, DateTime? expirationDate)
|
||||
{
|
||||
var user = await _userRepository.GetByIdAsync(userId);
|
||||
await DisablePremiumAsync(user, expirationDate);
|
||||
}
|
||||
|
||||
public async Task DisablePremiumAsync(User user, DateTime? expirationDate)
|
||||
{
|
||||
if(user != null && user.Premium)
|
||||
{
|
||||
user.Premium = false;
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using System;
|
||||
using Bit.Core.Models.Business;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
@ -27,9 +28,9 @@ namespace Bit.Core.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool VerifyUserPremium(User user)
|
||||
public Task<bool> VerifyUserPremiumAsync(User user)
|
||||
{
|
||||
return user.Premium;
|
||||
return Task.FromResult(user.Premium);
|
||||
}
|
||||
|
||||
public byte[] SignLicense(ILicense license)
|
||||
|
Loading…
Reference in New Issue
Block a user