mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 15:42:48 -05:00
more premium licensing
This commit is contained in:
@ -25,6 +25,7 @@ namespace Bit.Api.Controllers
|
|||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
private readonly ICipherService _cipherService;
|
private readonly ICipherService _cipherService;
|
||||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
|
private readonly ILicensingService _licenseService;
|
||||||
private readonly UserManager<User> _userManager;
|
private readonly UserManager<User> _userManager;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ namespace Bit.Api.Controllers
|
|||||||
IUserService userService,
|
IUserService userService,
|
||||||
ICipherService cipherService,
|
ICipherService cipherService,
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
|
ILicensingService licenseService,
|
||||||
UserManager<User> userManager,
|
UserManager<User> userManager,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
{
|
{
|
||||||
@ -39,6 +41,7 @@ namespace Bit.Api.Controllers
|
|||||||
_cipherService = cipherService;
|
_cipherService = cipherService;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
|
_licenseService = licenseService;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,7 +394,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
var valid = model.Validate(_globalSettings);
|
var valid = model.Validate(_globalSettings);
|
||||||
UserLicense license = null;
|
UserLicense license = null;
|
||||||
if(valid && model.License != null)
|
if(valid && _globalSettings.SelfHosted && model.License != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -434,7 +437,7 @@ namespace Bit.Api.Controllers
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BillingResponseModel(user, billingInfo);
|
return new BillingResponseModel(user, billingInfo, _licenseService);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("payment")]
|
[HttpPut("payment")]
|
||||||
|
@ -2,24 +2,25 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Stripe;
|
|
||||||
using Bit.Core.Models.Table;
|
using Bit.Core.Models.Table;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
|
||||||
namespace Bit.Core.Models.Api
|
namespace Bit.Core.Models.Api
|
||||||
{
|
{
|
||||||
public class BillingResponseModel : ResponseModel
|
public class BillingResponseModel : ResponseModel
|
||||||
{
|
{
|
||||||
public BillingResponseModel(IStorable storable, BillingInfo billing)
|
public BillingResponseModel(User user, BillingInfo billing, ILicensingService licenseService)
|
||||||
: base("billing")
|
: base("billing")
|
||||||
{
|
{
|
||||||
PaymentSource = billing.PaymentSource != null ? new BillingSource(billing.PaymentSource) : null;
|
PaymentSource = billing.PaymentSource != null ? new BillingSource(billing.PaymentSource) : null;
|
||||||
Subscription = billing.Subscription != null ? new BillingSubscription(billing.Subscription) : null;
|
Subscription = billing.Subscription != null ? new BillingSubscription(billing.Subscription) : null;
|
||||||
Charges = billing.Charges.Select(c => new BillingCharge(c));
|
Charges = billing.Charges.Select(c => new BillingCharge(c));
|
||||||
UpcomingInvoice = billing.UpcomingInvoice != null ? new BillingInvoice(billing.UpcomingInvoice) : null;
|
UpcomingInvoice = billing.UpcomingInvoice != null ? new BillingInvoice(billing.UpcomingInvoice) : null;
|
||||||
StorageName = storable.Storage.HasValue ? Utilities.CoreHelpers.ReadableBytesSize(storable.Storage.Value) : null;
|
StorageName = user.Storage.HasValue ? Utilities.CoreHelpers.ReadableBytesSize(user.Storage.Value) : null;
|
||||||
StorageGb = storable.Storage.HasValue ? Math.Round(storable.Storage.Value / 1073741824D, 2) : 0; // 1 GB
|
StorageGb = user.Storage.HasValue ? Math.Round(user.Storage.Value / 1073741824D, 2) : 0; // 1 GB
|
||||||
MaxStorageGb = storable.MaxStorageGb;
|
MaxStorageGb = user.MaxStorageGb;
|
||||||
|
License = new UserLicense(user, billing, licenseService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string StorageName { get; set; }
|
public string StorageName { get; set; }
|
||||||
@ -29,6 +30,7 @@ namespace Bit.Core.Models.Api
|
|||||||
public BillingSubscription Subscription { get; set; }
|
public BillingSubscription Subscription { get; set; }
|
||||||
public BillingInvoice UpcomingInvoice { get; set; }
|
public BillingInvoice UpcomingInvoice { get; set; }
|
||||||
public IEnumerable<BillingCharge> Charges { get; set; }
|
public IEnumerable<BillingCharge> Charges { get; set; }
|
||||||
|
public UserLicense License { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BillingSource
|
public class BillingSource
|
||||||
|
@ -8,10 +8,11 @@ namespace Bit.Core.Models.Business
|
|||||||
string LicenseKey { get; set; }
|
string LicenseKey { get; set; }
|
||||||
int Version { get; set; }
|
int Version { get; set; }
|
||||||
DateTime Issued { get; set; }
|
DateTime Issued { get; set; }
|
||||||
DateTime Expires { get; set; }
|
DateTime? Expires { get; set; }
|
||||||
bool Trial { get; set; }
|
bool Trial { get; set; }
|
||||||
string Signature { get; set; }
|
string Signature { get; set; }
|
||||||
byte[] GetSignatureData();
|
byte[] GetSignatureData();
|
||||||
bool VerifySignature(X509Certificate2 certificate);
|
bool VerifySignature(X509Certificate2 certificate);
|
||||||
|
byte[] Sign(X509Certificate2 certificate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace Bit.Core.Models.Business
|
|||||||
public bool SelfHost { get; set; }
|
public bool SelfHost { get; set; }
|
||||||
public int Version { get; set; }
|
public int Version { get; set; }
|
||||||
public DateTime Issued { get; set; }
|
public DateTime Issued { get; set; }
|
||||||
public DateTime Expires { get; set; }
|
public DateTime? Expires { get; set; }
|
||||||
public bool Trial { get; set; }
|
public bool Trial { get; set; }
|
||||||
public string Signature { get; set; }
|
public string Signature { get; set; }
|
||||||
public byte[] SignatureBytes => Convert.FromBase64String(Signature);
|
public byte[] SignatureBytes => Convert.FromBase64String(Signature);
|
||||||
@ -55,8 +55,8 @@ namespace Bit.Core.Models.Business
|
|||||||
{
|
{
|
||||||
data = string.Format("organization:{0}_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}_{11}_{12}_{13}",
|
data = string.Format("organization:{0}_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}_{11}_{12}_{13}",
|
||||||
Version,
|
Version,
|
||||||
Utilities.CoreHelpers.ToEpocMilliseconds(Issued),
|
Utilities.CoreHelpers.ToEpocSeconds(Issued),
|
||||||
Utilities.CoreHelpers.ToEpocMilliseconds(Expires),
|
Expires.HasValue ? Utilities.CoreHelpers.ToEpocSeconds(Expires.Value).ToString() : null,
|
||||||
LicenseKey,
|
LicenseKey,
|
||||||
Id,
|
Id,
|
||||||
Enabled,
|
Enabled,
|
||||||
@ -76,7 +76,7 @@ namespace Bit.Core.Models.Business
|
|||||||
|
|
||||||
return Encoding.UTF8.GetBytes(data);
|
return Encoding.UTF8.GetBytes(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool VerifyData(Organization organization)
|
public bool VerifyData(Organization organization)
|
||||||
{
|
{
|
||||||
if(Issued > DateTime.UtcNow)
|
if(Issued > DateTime.UtcNow)
|
||||||
@ -115,5 +115,10 @@ namespace Bit.Core.Models.Business
|
|||||||
return rsa.VerifyData(GetSignatureData(), SignatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
return rsa.VerifyData(GetSignatureData(), SignatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] Sign(X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using Bit.Core.Models.Table;
|
using Bit.Core.Models.Table;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
@ -11,12 +13,19 @@ namespace Bit.Core.Models.Business
|
|||||||
public UserLicense()
|
public UserLicense()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public UserLicense(User user)
|
public UserLicense(User user, BillingInfo billingInfo, ILicensingService licenseService)
|
||||||
{
|
{
|
||||||
LicenseKey = "";
|
LicenseKey = user.LicenseKey;
|
||||||
Id = user.Id;
|
Id = user.Id;
|
||||||
Email = user.Email;
|
Email = user.Email;
|
||||||
Version = 1;
|
Version = 1;
|
||||||
|
Premium = user.Premium;
|
||||||
|
MaxStorageGb = user.MaxStorageGb;
|
||||||
|
Issued = DateTime.UtcNow;
|
||||||
|
Expires = billingInfo?.UpcomingInvoice?.Date;
|
||||||
|
Trial = (billingInfo?.Subscription?.TrialEndDate.HasValue ?? false) &&
|
||||||
|
billingInfo.Subscription.TrialEndDate.Value > DateTime.UtcNow;
|
||||||
|
Signature = Convert.ToBase64String(licenseService.SignLicense(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string LicenseKey { get; set; }
|
public string LicenseKey { get; set; }
|
||||||
@ -26,9 +35,10 @@ namespace Bit.Core.Models.Business
|
|||||||
public short? MaxStorageGb { get; set; }
|
public short? MaxStorageGb { get; set; }
|
||||||
public int Version { get; set; }
|
public int Version { get; set; }
|
||||||
public DateTime Issued { get; set; }
|
public DateTime Issued { get; set; }
|
||||||
public DateTime Expires { get; set; }
|
public DateTime? Expires { get; set; }
|
||||||
public bool Trial { get; set; }
|
public bool Trial { get; set; }
|
||||||
public string Signature { get; set; }
|
public string Signature { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
public byte[] SignatureBytes => Convert.FromBase64String(Signature);
|
public byte[] SignatureBytes => Convert.FromBase64String(Signature);
|
||||||
|
|
||||||
public byte[] GetSignatureData()
|
public byte[] GetSignatureData()
|
||||||
@ -36,11 +46,12 @@ namespace Bit.Core.Models.Business
|
|||||||
string data = null;
|
string data = null;
|
||||||
if(Version == 1)
|
if(Version == 1)
|
||||||
{
|
{
|
||||||
data = string.Format("user:{0}_{1}_{2}_{3}_{4}_{5}_{6}_{7}",
|
data = string.Format("user:{0}_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}",
|
||||||
Version,
|
Version,
|
||||||
Utilities.CoreHelpers.ToEpocMilliseconds(Issued),
|
Utilities.CoreHelpers.ToEpocSeconds(Issued),
|
||||||
Utilities.CoreHelpers.ToEpocMilliseconds(Expires),
|
Expires.HasValue ? Utilities.CoreHelpers.ToEpocSeconds(Expires.Value).ToString() : null,
|
||||||
LicenseKey,
|
LicenseKey,
|
||||||
|
Trial,
|
||||||
Id,
|
Id,
|
||||||
Email,
|
Email,
|
||||||
Premium,
|
Premium,
|
||||||
@ -86,5 +97,18 @@ namespace Bit.Core.Models.Business
|
|||||||
return rsa.VerifyData(GetSignatureData(), SignatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
return rsa.VerifyData(GetSignatureData(), SignatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] Sign(X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
if(!certificate.HasPrivateKey)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("You don't have the private key!");
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var rsa = certificate.GetRSAPrivateKey())
|
||||||
|
{
|
||||||
|
return rsa.SignData(GetSignatureData(), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,11 @@ using Bit.Core.Models.Table;
|
|||||||
|
|
||||||
namespace Bit.Core.Services
|
namespace Bit.Core.Services
|
||||||
{
|
{
|
||||||
public interface ILicenseVerificationService
|
public interface ILicensingService
|
||||||
{
|
{
|
||||||
bool VerifyOrganizationPlan(Organization organization);
|
bool VerifyOrganizationPlan(Organization organization);
|
||||||
bool VerifyUserPremium(User user);
|
bool VerifyUserPremium(User user);
|
||||||
bool VerifyLicense(ILicense license);
|
bool VerifyLicense(ILicense license);
|
||||||
|
byte[] SignLicense(ILicense license);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -106,7 +106,7 @@ namespace Bit.Core.Services
|
|||||||
throw new InvalidOperationException("No exp in token.");
|
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;
|
return DateTime.UtcNow < expiration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,26 +11,23 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Bit.Core.Services
|
namespace Bit.Core.Services
|
||||||
{
|
{
|
||||||
public class RsaLicenseVerificationService : ILicenseVerificationService
|
public class RsaLicensingService : ILicensingService
|
||||||
{
|
{
|
||||||
private readonly X509Certificate2 _certificate;
|
private readonly X509Certificate2 _certificate;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
private IDictionary<string, UserLicense> _userLicenseCache;
|
private IDictionary<string, UserLicense> _userLicenseCache;
|
||||||
private IDictionary<string, OrganizationLicense> _organizationLicenseCache;
|
private IDictionary<string, OrganizationLicense> _organizationLicenseCache;
|
||||||
|
|
||||||
public RsaLicenseVerificationService(
|
public RsaLicensingService(
|
||||||
IHostingEnvironment environment,
|
IHostingEnvironment environment,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
{
|
{
|
||||||
if(!environment.IsDevelopment() && !globalSettings.SelfHosted)
|
var certThumbprint = "207e64a231e8aa32aaf68a61037c075ebebd553f";
|
||||||
{
|
|
||||||
throw new Exception($"{nameof(RsaLicenseVerificationService)} can only be used for self hosted instances.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
_certificate = CoreHelpers.GetEmbeddedCertificate("licensing.cer", null);
|
_certificate = !_globalSettings.SelfHosted ? CoreHelpers.GetCertificate(certThumbprint)
|
||||||
if(!_certificate.Thumbprint.Equals(CoreHelpers.CleanCertificateThumbprint(
|
: CoreHelpers.GetEmbeddedCertificate("licensing.cer", null);
|
||||||
"207e64a231e8aa32aaf68a61037c075ebebd553f"), StringComparison.InvariantCultureIgnoreCase))
|
if(_certificate == null || !_certificate.Thumbprint.Equals(CoreHelpers.CleanCertificateThumbprint(certThumbprint),
|
||||||
|
StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
throw new Exception("Invalid licensing certificate.");
|
throw new Exception("Invalid licensing certificate.");
|
||||||
}
|
}
|
||||||
@ -43,7 +40,12 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public bool VerifyOrganizationPlan(Organization organization)
|
public bool VerifyOrganizationPlan(Organization organization)
|
||||||
{
|
{
|
||||||
if(_globalSettings.SelfHosted && !organization.SelfHost)
|
if(!_globalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!organization.SelfHost)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -54,6 +56,11 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public bool VerifyUserPremium(User user)
|
public bool VerifyUserPremium(User user)
|
||||||
{
|
{
|
||||||
|
if(!_globalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
return user.Premium;
|
||||||
|
}
|
||||||
|
|
||||||
if(!user.Premium)
|
if(!user.Premium)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -68,6 +75,16 @@ namespace Bit.Core.Services
|
|||||||
return license.VerifySignature(_certificate);
|
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)
|
private UserLicense ReadUserLicense(User user)
|
||||||
{
|
{
|
||||||
if(_userLicenseCache != null && _userLicenseCache.ContainsKey(user.LicenseKey))
|
if(_userLicenseCache != null && _userLicenseCache.ContainsKey(user.LicenseKey))
|
||||||
@ -75,7 +92,7 @@ namespace Bit.Core.Services
|
|||||||
return _userLicenseCache[user.LicenseKey];
|
return _userLicenseCache[user.LicenseKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
var filePath = $"{_globalSettings.LicenseDirectory}/user/{user.LicenseKey}.json";
|
var filePath = $"{_globalSettings.LicenseDirectory}/user/{user.Id}.json";
|
||||||
if(!File.Exists(filePath))
|
if(!File.Exists(filePath))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@ -98,7 +115,7 @@ namespace Bit.Core.Services
|
|||||||
return _organizationLicenseCache[organization.LicenseKey];
|
return _organizationLicenseCache[organization.LicenseKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
var filePath = $"{_globalSettings.LicenseDirectory}/organization/{organization.LicenseKey}.json";
|
var filePath = $"{_globalSettings.LicenseDirectory}/organization/{organization.Id}.json";
|
||||||
if(!File.Exists(filePath))
|
if(!File.Exists(filePath))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
@ -37,7 +37,7 @@ namespace Bit.Core.Services
|
|||||||
private readonly IdentityOptions _identityOptions;
|
private readonly IdentityOptions _identityOptions;
|
||||||
private readonly IPasswordHasher<User> _passwordHasher;
|
private readonly IPasswordHasher<User> _passwordHasher;
|
||||||
private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators;
|
private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators;
|
||||||
private readonly ILicenseVerificationService _licenseVerificationService;
|
private readonly ILicensingService _licenseService;
|
||||||
private readonly CurrentContext _currentContext;
|
private readonly CurrentContext _currentContext;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ namespace Bit.Core.Services
|
|||||||
IdentityErrorDescriber errors,
|
IdentityErrorDescriber errors,
|
||||||
IServiceProvider services,
|
IServiceProvider services,
|
||||||
ILogger<UserManager<User>> logger,
|
ILogger<UserManager<User>> logger,
|
||||||
ILicenseVerificationService licenseVerificationService,
|
ILicensingService licenseService,
|
||||||
CurrentContext currentContext,
|
CurrentContext currentContext,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
: base(
|
: base(
|
||||||
@ -81,7 +81,7 @@ namespace Bit.Core.Services
|
|||||||
_identityErrorDescriber = errors;
|
_identityErrorDescriber = errors;
|
||||||
_passwordHasher = passwordHasher;
|
_passwordHasher = passwordHasher;
|
||||||
_passwordValidators = passwordValidators;
|
_passwordValidators = passwordValidators;
|
||||||
_licenseVerificationService = licenseVerificationService;
|
_licenseService = licenseService;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
}
|
}
|
||||||
@ -540,13 +540,14 @@ namespace Bit.Core.Services
|
|||||||
IPaymentService paymentService = null;
|
IPaymentService paymentService = null;
|
||||||
if(_globalSettings.SelfHosted)
|
if(_globalSettings.SelfHosted)
|
||||||
{
|
{
|
||||||
if(license == null || !_licenseVerificationService.VerifyLicense(license))
|
if(license == null || !_licenseService.VerifyLicense(license))
|
||||||
{
|
{
|
||||||
throw new BadRequestException("Invalid license.");
|
throw new BadRequestException("Invalid license.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(_globalSettings.LicenseDirectory);
|
var dir = $"{_globalSettings.LicenseDirectory}/user";
|
||||||
File.WriteAllText(_globalSettings.LicenseDirectory, JsonConvert.SerializeObject(license, Formatting.Indented));
|
Directory.CreateDirectory(dir);
|
||||||
|
File.WriteAllText($"{dir}/{user.Id}.json", JsonConvert.SerializeObject(license, Formatting.Indented));
|
||||||
}
|
}
|
||||||
else if(!string.IsNullOrWhiteSpace(paymentToken))
|
else if(!string.IsNullOrWhiteSpace(paymentToken))
|
||||||
{
|
{
|
||||||
@ -567,20 +568,26 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
user.Premium = true;
|
user.Premium = true;
|
||||||
user.MaxStorageGb = _globalSettings.SelfHosted ? (short)10240 : (short)(1 + additionalStorageGb);
|
|
||||||
user.RevisionDate = DateTime.UtcNow;
|
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
|
try
|
||||||
{
|
{
|
||||||
await SaveUserAsync(user);
|
await SaveUserAsync(user);
|
||||||
}
|
}
|
||||||
catch
|
catch when(!_globalSettings.SelfHosted)
|
||||||
{
|
{
|
||||||
if(!_globalSettings.SelfHosted)
|
await paymentService.CancelAndRecoverChargesAsync(user);
|
||||||
{
|
|
||||||
await paymentService.CancelAndRecoverChargesAsync(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,15 @@ using Bit.Core.Models.Business;
|
|||||||
|
|
||||||
namespace Bit.Core.Services
|
namespace Bit.Core.Services
|
||||||
{
|
{
|
||||||
public class NoopLicenseVerificationService : ILicenseVerificationService
|
public class NoopLicensingService : ILicensingService
|
||||||
{
|
{
|
||||||
public NoopLicenseVerificationService(
|
public NoopLicensingService(
|
||||||
IHostingEnvironment environment,
|
IHostingEnvironment environment,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
{
|
{
|
||||||
if(!environment.IsDevelopment() && globalSettings.SelfHosted)
|
if(!environment.IsDevelopment() && globalSettings.SelfHosted)
|
||||||
{
|
{
|
||||||
throw new Exception($"{nameof(NoopLicenseVerificationService)} cannot be used for self hosted instances.");
|
throw new Exception($"{nameof(NoopLicensingService)} cannot be used for self hosted instances.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,5 +31,10 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
return user.Premium;
|
return user.Premium;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] SignLicense(ILicense license)
|
||||||
|
{
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -146,6 +146,16 @@ namespace Bit.Core.Utilities
|
|||||||
return _epoc.AddMilliseconds(milliseconds);
|
return _epoc.AddMilliseconds(milliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long ToEpocSeconds(DateTime date)
|
||||||
|
{
|
||||||
|
return (long)Math.Round((date - _epoc).TotalSeconds, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime FromEpocSeconds(long seconds)
|
||||||
|
{
|
||||||
|
return _epoc.AddSeconds(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
public static string U2fAppIdUrl(GlobalSettings globalSettings)
|
public static string U2fAppIdUrl(GlobalSettings globalSettings)
|
||||||
{
|
{
|
||||||
return string.Concat(globalSettings.BaseServiceUri.Vault, "/app-id.json");
|
return string.Concat(globalSettings.BaseServiceUri.Vault, "/app-id.json");
|
||||||
|
@ -55,6 +55,7 @@ namespace Bit.Core.Utilities
|
|||||||
public static void AddDefaultServices(this IServiceCollection services, GlobalSettings globalSettings)
|
public static void AddDefaultServices(this IServiceCollection services, GlobalSettings globalSettings)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IMailService, RazorViewMailService>();
|
services.AddSingleton<IMailService, RazorViewMailService>();
|
||||||
|
services.AddSingleton<ILicensingService, RsaLicensingService>();
|
||||||
|
|
||||||
if(CoreHelpers.SettingHasValue(globalSettings.Mail.SendGridApiKey))
|
if(CoreHelpers.SettingHasValue(globalSettings.Mail.SendGridApiKey))
|
||||||
{
|
{
|
||||||
@ -113,15 +114,6 @@ namespace Bit.Core.Utilities
|
|||||||
{
|
{
|
||||||
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(globalSettings.SelfHosted)
|
|
||||||
{
|
|
||||||
services.AddSingleton<ILicenseVerificationService, RsaLicenseVerificationService>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
services.AddSingleton<ILicenseVerificationService, NoopLicenseVerificationService>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddNoopServices(this IServiceCollection services)
|
public static void AddNoopServices(this IServiceCollection services)
|
||||||
@ -132,7 +124,7 @@ namespace Bit.Core.Utilities
|
|||||||
services.AddSingleton<IBlockIpService, NoopBlockIpService>();
|
services.AddSingleton<IBlockIpService, NoopBlockIpService>();
|
||||||
services.AddSingleton<IPushRegistrationService, NoopPushRegistrationService>();
|
services.AddSingleton<IPushRegistrationService, NoopPushRegistrationService>();
|
||||||
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
||||||
services.AddSingleton<ILicenseVerificationService, NoopLicenseVerificationService>();
|
services.AddSingleton<ILicensingService, NoopLicensingService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IdentityBuilder AddCustomIdentityServices(
|
public static IdentityBuilder AddCustomIdentityServices(
|
||||||
|
Reference in New Issue
Block a user