mirror of
https://github.com/bitwarden/server.git
synced 2025-04-07 05:58:13 -05:00
update premium license and self host attr checks
This commit is contained in:
parent
9e566e90a9
commit
18cbc79dd2
@ -15,6 +15,7 @@ using Bit.Core;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
|
using Bit.Api.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers
|
namespace Bit.Api.Controllers
|
||||||
{
|
{
|
||||||
@ -458,6 +459,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
[HttpPut("payment")]
|
[HttpPut("payment")]
|
||||||
[HttpPost("payment")]
|
[HttpPost("payment")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutPayment([FromBody]PaymentRequestModel model)
|
public async Task PutPayment([FromBody]PaymentRequestModel model)
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
@ -471,6 +473,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
[HttpPut("storage")]
|
[HttpPut("storage")]
|
||||||
[HttpPost("storage")]
|
[HttpPost("storage")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutStorage([FromBody]StorageRequestModel model)
|
public async Task PutStorage([FromBody]StorageRequestModel model)
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
@ -482,8 +485,46 @@ namespace Bit.Api.Controllers
|
|||||||
await _userService.AdjustStorageAsync(user, model.StorageGbAdjustment.Value);
|
await _userService.AdjustStorageAsync(user, model.StorageGbAdjustment.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPut("license")]
|
||||||
|
[HttpPost("license")]
|
||||||
|
[SelfHosted(SelfHostedOnly = true)]
|
||||||
|
public async Task PutLicense(UpdateLicenseRequestModel model)
|
||||||
|
{
|
||||||
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
|
if(user == null)
|
||||||
|
{
|
||||||
|
throw new UnauthorizedAccessException();
|
||||||
|
}
|
||||||
|
|
||||||
|
UserLicense license = null;
|
||||||
|
if(HttpContext.Request.ContentLength.HasValue && HttpContext.Request.ContentLength.Value <= 51200) // 50 KB
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using(var stream = model.License.OpenReadStream())
|
||||||
|
using(var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
var s = await reader.ReadToEndAsync();
|
||||||
|
if(!string.IsNullOrWhiteSpace(s))
|
||||||
|
{
|
||||||
|
license = JsonConvert.DeserializeObject<UserLicense>(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(license == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Invalid license");
|
||||||
|
}
|
||||||
|
|
||||||
|
await _userService.UpdateLicenseAsync(user, license);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPut("cancel-premium")]
|
[HttpPut("cancel-premium")]
|
||||||
[HttpPost("cancel-premium")]
|
[HttpPost("cancel-premium")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutCancel()
|
public async Task PutCancel()
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
@ -497,6 +538,7 @@ namespace Bit.Api.Controllers
|
|||||||
|
|
||||||
[HttpPut("reinstate-premium")]
|
[HttpPut("reinstate-premium")]
|
||||||
[HttpPost("reinstate-premium")]
|
[HttpPost("reinstate-premium")]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task PutReinstate()
|
public async Task PutReinstate()
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
|
26
src/Api/Utilities/SelfHostedAttribute.cs
Normal file
26
src/Api/Utilities/SelfHostedAttribute.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Bit.Core;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
|
|
||||||
|
namespace Bit.Api.Utilities
|
||||||
|
{
|
||||||
|
public class SelfHostedAttribute : ActionFilterAttribute
|
||||||
|
{
|
||||||
|
public bool SelfHostedOnly { get; set; }
|
||||||
|
public bool NotSelfHostedOnly { get; set; }
|
||||||
|
|
||||||
|
public override void OnActionExecuting(ActionExecutingContext context)
|
||||||
|
{
|
||||||
|
var globalSettings = context.HttpContext.RequestServices.GetRequiredService<GlobalSettings>();
|
||||||
|
if(SelfHostedOnly && !globalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Only allowed when self hosted.");
|
||||||
|
}
|
||||||
|
else if(NotSelfHostedOnly && globalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Only allowed when not self hosted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class UpdateLicenseRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public IFormFile License { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ namespace Bit.Core.Models.Api
|
|||||||
StorageGb = user.Storage.HasValue ? Math.Round(user.Storage.Value / 1073741824D, 2) : 0; // 1 GB
|
StorageGb = user.Storage.HasValue ? Math.Round(user.Storage.Value / 1073741824D, 2) : 0; // 1 GB
|
||||||
MaxStorageGb = user.MaxStorageGb;
|
MaxStorageGb = user.MaxStorageGb;
|
||||||
License = new UserLicense(user, billing, licenseService);
|
License = new UserLicense(user, billing, licenseService);
|
||||||
|
Expiration = License.Expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BillingResponseModel(User user)
|
public BillingResponseModel(User user)
|
||||||
@ -29,6 +30,7 @@ namespace Bit.Core.Models.Api
|
|||||||
StorageName = user.Storage.HasValue ? Utilities.CoreHelpers.ReadableBytesSize(user.Storage.Value) : null;
|
StorageName = user.Storage.HasValue ? Utilities.CoreHelpers.ReadableBytesSize(user.Storage.Value) : null;
|
||||||
StorageGb = user.Storage.HasValue ? Math.Round(user.Storage.Value / 1073741824D, 2) : 0; // 1 GB
|
StorageGb = user.Storage.HasValue ? Math.Round(user.Storage.Value / 1073741824D, 2) : 0; // 1 GB
|
||||||
MaxStorageGb = user.MaxStorageGb;
|
MaxStorageGb = user.MaxStorageGb;
|
||||||
|
Expiration = user.PremiumExpirationDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string StorageName { get; set; }
|
public string StorageName { get; set; }
|
||||||
@ -39,6 +41,7 @@ namespace Bit.Core.Models.Api
|
|||||||
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 UserLicense License { get; set; }
|
||||||
|
public DateTime? Expiration { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BillingSource
|
public class BillingSource
|
||||||
|
@ -41,6 +41,7 @@ namespace Bit.Core.Services
|
|||||||
Task<IdentityResult> DeleteAsync(User user, string token);
|
Task<IdentityResult> DeleteAsync(User user, string token);
|
||||||
Task SendDeleteConfirmationAsync(string email);
|
Task SendDeleteConfirmationAsync(string email);
|
||||||
Task SignUpPremiumAsync(User user, string paymentToken, short additionalStorageGb, UserLicense license);
|
Task SignUpPremiumAsync(User user, string paymentToken, short additionalStorageGb, UserLicense license);
|
||||||
|
Task UpdateLicenseAsync(User user, UserLicense license);
|
||||||
Task AdjustStorageAsync(User user, short storageAdjustmentGb);
|
Task AdjustStorageAsync(User user, short storageAdjustmentGb);
|
||||||
Task ReplacePaymentMethodAsync(User user, string paymentToken);
|
Task ReplacePaymentMethodAsync(User user, string paymentToken);
|
||||||
Task CancelPremiumAsync(User user, bool endOfPeriod = false);
|
Task CancelPremiumAsync(User user, bool endOfPeriod = false);
|
||||||
|
@ -598,6 +598,30 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdateLicenseAsync(User user, UserLicense license)
|
||||||
|
{
|
||||||
|
if(!_globalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Licenses require self hosting.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(license == null || !_licenseService.VerifyLicense(license))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Invalid license.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var dir = $"{_globalSettings.LicenseDirectory}/user";
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
File.WriteAllText($"{dir}/{user.Id}.json", JsonConvert.SerializeObject(license, Formatting.Indented));
|
||||||
|
|
||||||
|
user.Premium = true;
|
||||||
|
user.RevisionDate = DateTime.UtcNow;
|
||||||
|
user.MaxStorageGb = 10240; // 10 TB
|
||||||
|
user.LicenseKey = license.LicenseKey;
|
||||||
|
user.PremiumExpirationDate = license.Expires;
|
||||||
|
await SaveUserAsync(user);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task AdjustStorageAsync(User user, short storageAdjustmentGb)
|
public async Task AdjustStorageAsync(User user, short storageAdjustmentGb)
|
||||||
{
|
{
|
||||||
if(user == null)
|
if(user == null)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user