mirror of
https://github.com/bitwarden/server.git
synced 2025-07-02 00:22:50 -05:00
more premium licensing
This commit is contained in:
@ -106,7 +106,7 @@ namespace Bit.Core.Services
|
||||
throw new InvalidOperationException("No exp in token.");
|
||||
}
|
||||
|
||||
var expiration = CoreHelpers.FromEpocMilliseconds(1000 * exp.Value<long>());
|
||||
var expiration = CoreHelpers.FromEpocSeconds(exp.Value<long>());
|
||||
return DateTime.UtcNow < expiration;
|
||||
}
|
||||
|
||||
|
@ -11,26 +11,23 @@ using System.Text;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public class RsaLicenseVerificationService : ILicenseVerificationService
|
||||
public class RsaLicensingService : ILicensingService
|
||||
{
|
||||
private readonly X509Certificate2 _certificate;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private IDictionary<string, UserLicense> _userLicenseCache;
|
||||
private IDictionary<string, OrganizationLicense> _organizationLicenseCache;
|
||||
|
||||
public RsaLicenseVerificationService(
|
||||
public RsaLicensingService(
|
||||
IHostingEnvironment environment,
|
||||
GlobalSettings globalSettings)
|
||||
{
|
||||
if(!environment.IsDevelopment() && !globalSettings.SelfHosted)
|
||||
{
|
||||
throw new Exception($"{nameof(RsaLicenseVerificationService)} can only be used for self hosted instances.");
|
||||
}
|
||||
|
||||
var certThumbprint = "207e64a231e8aa32aaf68a61037c075ebebd553f";
|
||||
_globalSettings = globalSettings;
|
||||
_certificate = CoreHelpers.GetEmbeddedCertificate("licensing.cer", null);
|
||||
if(!_certificate.Thumbprint.Equals(CoreHelpers.CleanCertificateThumbprint(
|
||||
"207e64a231e8aa32aaf68a61037c075ebebd553f"), StringComparison.InvariantCultureIgnoreCase))
|
||||
_certificate = !_globalSettings.SelfHosted ? CoreHelpers.GetCertificate(certThumbprint)
|
||||
: CoreHelpers.GetEmbeddedCertificate("licensing.cer", null);
|
||||
if(_certificate == null || !_certificate.Thumbprint.Equals(CoreHelpers.CleanCertificateThumbprint(certThumbprint),
|
||||
StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
throw new Exception("Invalid licensing certificate.");
|
||||
}
|
||||
@ -43,7 +40,12 @@ namespace Bit.Core.Services
|
||||
|
||||
public bool VerifyOrganizationPlan(Organization organization)
|
||||
{
|
||||
if(_globalSettings.SelfHosted && !organization.SelfHost)
|
||||
if(!_globalSettings.SelfHosted)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!organization.SelfHost)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -54,6 +56,11 @@ namespace Bit.Core.Services
|
||||
|
||||
public bool VerifyUserPremium(User user)
|
||||
{
|
||||
if(!_globalSettings.SelfHosted)
|
||||
{
|
||||
return user.Premium;
|
||||
}
|
||||
|
||||
if(!user.Premium)
|
||||
{
|
||||
return false;
|
||||
@ -68,6 +75,16 @@ namespace Bit.Core.Services
|
||||
return license.VerifySignature(_certificate);
|
||||
}
|
||||
|
||||
public byte[] SignLicense(ILicense license)
|
||||
{
|
||||
if(_globalSettings.SelfHosted || !_certificate.HasPrivateKey)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot sign licenses.");
|
||||
}
|
||||
|
||||
return license.Sign(_certificate);
|
||||
}
|
||||
|
||||
private UserLicense ReadUserLicense(User user)
|
||||
{
|
||||
if(_userLicenseCache != null && _userLicenseCache.ContainsKey(user.LicenseKey))
|
||||
@ -75,7 +92,7 @@ namespace Bit.Core.Services
|
||||
return _userLicenseCache[user.LicenseKey];
|
||||
}
|
||||
|
||||
var filePath = $"{_globalSettings.LicenseDirectory}/user/{user.LicenseKey}.json";
|
||||
var filePath = $"{_globalSettings.LicenseDirectory}/user/{user.Id}.json";
|
||||
if(!File.Exists(filePath))
|
||||
{
|
||||
return null;
|
||||
@ -98,7 +115,7 @@ namespace Bit.Core.Services
|
||||
return _organizationLicenseCache[organization.LicenseKey];
|
||||
}
|
||||
|
||||
var filePath = $"{_globalSettings.LicenseDirectory}/organization/{organization.LicenseKey}.json";
|
||||
var filePath = $"{_globalSettings.LicenseDirectory}/organization/{organization.Id}.json";
|
||||
if(!File.Exists(filePath))
|
||||
{
|
||||
return null;
|
@ -37,7 +37,7 @@ namespace Bit.Core.Services
|
||||
private readonly IdentityOptions _identityOptions;
|
||||
private readonly IPasswordHasher<User> _passwordHasher;
|
||||
private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators;
|
||||
private readonly ILicenseVerificationService _licenseVerificationService;
|
||||
private readonly ILicensingService _licenseService;
|
||||
private readonly CurrentContext _currentContext;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
@ -57,7 +57,7 @@ namespace Bit.Core.Services
|
||||
IdentityErrorDescriber errors,
|
||||
IServiceProvider services,
|
||||
ILogger<UserManager<User>> logger,
|
||||
ILicenseVerificationService licenseVerificationService,
|
||||
ILicensingService licenseService,
|
||||
CurrentContext currentContext,
|
||||
GlobalSettings globalSettings)
|
||||
: base(
|
||||
@ -81,7 +81,7 @@ namespace Bit.Core.Services
|
||||
_identityErrorDescriber = errors;
|
||||
_passwordHasher = passwordHasher;
|
||||
_passwordValidators = passwordValidators;
|
||||
_licenseVerificationService = licenseVerificationService;
|
||||
_licenseService = licenseService;
|
||||
_currentContext = currentContext;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
@ -540,13 +540,14 @@ namespace Bit.Core.Services
|
||||
IPaymentService paymentService = null;
|
||||
if(_globalSettings.SelfHosted)
|
||||
{
|
||||
if(license == null || !_licenseVerificationService.VerifyLicense(license))
|
||||
if(license == null || !_licenseService.VerifyLicense(license))
|
||||
{
|
||||
throw new BadRequestException("Invalid license.");
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(_globalSettings.LicenseDirectory);
|
||||
File.WriteAllText(_globalSettings.LicenseDirectory, JsonConvert.SerializeObject(license, Formatting.Indented));
|
||||
var dir = $"{_globalSettings.LicenseDirectory}/user";
|
||||
Directory.CreateDirectory(dir);
|
||||
File.WriteAllText($"{dir}/{user.Id}.json", JsonConvert.SerializeObject(license, Formatting.Indented));
|
||||
}
|
||||
else if(!string.IsNullOrWhiteSpace(paymentToken))
|
||||
{
|
||||
@ -567,20 +568,26 @@ namespace Bit.Core.Services
|
||||
}
|
||||
|
||||
user.Premium = true;
|
||||
user.MaxStorageGb = _globalSettings.SelfHosted ? (short)10240 : (short)(1 + additionalStorageGb);
|
||||
user.RevisionDate = DateTime.UtcNow;
|
||||
|
||||
if(_globalSettings.SelfHosted)
|
||||
{
|
||||
user.MaxStorageGb = 10240;
|
||||
user.LicenseKey = license.LicenseKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
user.MaxStorageGb = (short)(1 + additionalStorageGb);
|
||||
user.LicenseKey = CoreHelpers.SecureRandomString(20, upper: false);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await SaveUserAsync(user);
|
||||
}
|
||||
catch
|
||||
catch when(!_globalSettings.SelfHosted)
|
||||
{
|
||||
if(!_globalSettings.SelfHosted)
|
||||
{
|
||||
await paymentService.CancelAndRecoverChargesAsync(user);
|
||||
}
|
||||
|
||||
await paymentService.CancelAndRecoverChargesAsync(user);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user