1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-08 04:00:31 -05:00

Updated expiration, refresh, and isTrial logic to ensure it matches the original logic

This commit is contained in:
Conner Turnbull 2025-06-06 14:19:52 -04:00
parent 71cb4a4ea8
commit a4a9af9863
No known key found for this signature in database
4 changed files with 86 additions and 112 deletions

View File

@ -116,23 +116,51 @@ public static class LicenseExtensions
public static class OrganizationLicenseExtensions public static class OrganizationLicenseExtensions
{ {
public static DateTime CalculateFreshExpirationDate(this Organization org, SubscriptionInfo subscriptionInfo) public static DateTime CalculateFreshExpirationDate(this Organization org, SubscriptionInfo subscriptionInfo, DateTime issued)
{ {
if (subscriptionInfo?.Subscription == null) if (subscriptionInfo?.Subscription == null)
{ {
if (org.PlanType == PlanType.Custom && org.ExpirationDate.HasValue) return org.PlanType == PlanType.Custom && org.ExpirationDate.HasValue
{ ? org.ExpirationDate.Value
return org.ExpirationDate.Value; : issued.AddDays(7);
}
return DateTime.UtcNow.AddDays(7);
} }
var subscription = subscriptionInfo.Subscription; if (subscriptionInfo.Subscription.TrialEndDate.HasValue &&
subscriptionInfo.Subscription.TrialEndDate.Value > DateTime.UtcNow)
if (subscription.TrialEndDate > DateTime.UtcNow)
{ {
return subscription.TrialEndDate.Value; return subscriptionInfo.Subscription.TrialEndDate.Value;
}
if (org.ExpirationDate.HasValue && org.ExpirationDate.Value < DateTime.UtcNow)
{
// expired
return org.ExpirationDate.Value;
}
if (subscriptionInfo?.Subscription?.PeriodDuration != null &&
subscriptionInfo.Subscription.PeriodDuration > TimeSpan.FromDays(180))
{
return subscriptionInfo.Subscription.PeriodEndDate.Value.AddDays(Core.Constants.OrganizationSelfHostSubscriptionGracePeriodDays);
}
return org.ExpirationDate.HasValue
? org.ExpirationDate.Value.AddMonths(11)
: issued.AddYears(1);
}
public static DateTime CalculateFreshRefreshDate(this Organization org, SubscriptionInfo subscriptionInfo, DateTime? expirationDate, DateTime issued)
{
if (subscriptionInfo?.Subscription == null)
{
return org.PlanType == PlanType.Custom && org.ExpirationDate.HasValue
? org.ExpirationDate.Value
: issued.AddDays(7);
}
if (subscriptionInfo.Subscription.TrialEndDate.HasValue &&
subscriptionInfo.Subscription.TrialEndDate.Value > DateTime.UtcNow)
{
return subscriptionInfo.Subscription.TrialEndDate.Value;
} }
if (org.ExpirationDate.HasValue && org.ExpirationDate.Value < DateTime.UtcNow) if (org.ExpirationDate.HasValue && org.ExpirationDate.Value < DateTime.UtcNow)
@ -140,66 +168,48 @@ public static class OrganizationLicenseExtensions
return org.ExpirationDate.Value; return org.ExpirationDate.Value;
} }
if (subscription.PeriodEndDate.HasValue && subscription.PeriodDuration > TimeSpan.FromDays(180)) if (subscriptionInfo?.Subscription?.PeriodDuration != null &&
subscriptionInfo.Subscription.PeriodDuration > TimeSpan.FromDays(180))
{ {
return subscription.PeriodEndDate return DateTime.UtcNow.AddDays(30);
.Value
.AddDays(Bit.Core.Constants.OrganizationSelfHostSubscriptionGracePeriodDays);
} }
return org.ExpirationDate?.AddMonths(11) ?? DateTime.UtcNow.AddYears(1); return !expirationDate.HasValue || DateTime.UtcNow - expirationDate.Value > TimeSpan.FromDays(30)
}
public static DateTime CalculateFreshRefreshDate(this Organization org, SubscriptionInfo subscriptionInfo, DateTime expirationDate)
{
if (subscriptionInfo?.Subscription == null ||
subscriptionInfo.Subscription.TrialEndDate > DateTime.UtcNow ||
org.ExpirationDate < DateTime.UtcNow)
{
return expirationDate;
}
return subscriptionInfo.Subscription.PeriodDuration > TimeSpan.FromDays(180) ||
DateTime.UtcNow - expirationDate > TimeSpan.FromDays(30)
? DateTime.UtcNow.AddDays(30) ? DateTime.UtcNow.AddDays(30)
: expirationDate; : expirationDate.Value;
} }
public static DateTime CalculateFreshExpirationDateWithoutGracePeriod(this Organization org, SubscriptionInfo subscriptionInfo, DateTime expirationDate) public static DateTime? CalculateFreshExpirationDateWithoutGracePeriod(this Organization org, SubscriptionInfo subscriptionInfo) =>
{ subscriptionInfo?.Subscription != null &&
if (subscriptionInfo?.Subscription is null) (!subscriptionInfo.Subscription.TrialEndDate.HasValue || subscriptionInfo.Subscription.TrialEndDate.Value <= DateTime.UtcNow) &&
{ (!org.ExpirationDate.HasValue || org.ExpirationDate.Value >= DateTime.UtcNow) &&
return expirationDate; subscriptionInfo.Subscription.PeriodDuration != null &&
} subscriptionInfo.Subscription.PeriodDuration > TimeSpan.FromDays(180)
? subscriptionInfo.Subscription.PeriodEndDate
var subscription = subscriptionInfo.Subscription; : null;
if (subscription.TrialEndDate <= DateTime.UtcNow &&
org.ExpirationDate >= DateTime.UtcNow &&
subscription.PeriodEndDate.HasValue &&
subscription.PeriodDuration > TimeSpan.FromDays(180))
{
return subscription.PeriodEndDate.Value;
}
return expirationDate;
}
public static bool IsTrialing(this Organization org, SubscriptionInfo subscriptionInfo) => public static bool IsTrialing(this Organization org, SubscriptionInfo subscriptionInfo) =>
subscriptionInfo?.Subscription is null subscriptionInfo?.Subscription == null
? org.PlanType != PlanType.Custom || !org.ExpirationDate.HasValue ? org.PlanType != PlanType.Custom || !org.ExpirationDate.HasValue
: subscriptionInfo.Subscription.TrialEndDate > DateTime.UtcNow; : subscriptionInfo.Subscription.TrialEndDate.HasValue && subscriptionInfo.Subscription.TrialEndDate.Value > DateTime.UtcNow;
} }
public static class UserLicenseExtensions public static class UserLicenseExtensions
{ {
public static DateTime? CalculateFreshExpirationDate(this User user, SubscriptionInfo subscriptionInfo) => public static DateTime? CalculateFreshExpirationDate(this User user, SubscriptionInfo subscriptionInfo) =>
subscriptionInfo?.UpcomingInvoice?.Date?.AddDays(7) ?? user.PremiumExpirationDate?.AddDays(7); subscriptionInfo == null
? user.PremiumExpirationDate?.AddDays(7)
: subscriptionInfo.UpcomingInvoice?.Date != null
? subscriptionInfo.UpcomingInvoice.Date.Value.AddDays(7)
: user.PremiumExpirationDate?.AddDays(7);
public static DateTime? CalculateFreshRefreshDate(this User user, SubscriptionInfo subscriptionInfo) => public static DateTime? CalculateFreshRefreshDate(this User user, SubscriptionInfo subscriptionInfo) =>
subscriptionInfo?.UpcomingInvoice?.Date ?? user.PremiumExpirationDate; subscriptionInfo == null
? user.PremiumExpirationDate?.Date
: subscriptionInfo?.UpcomingInvoice?.Date;
public static bool IsTrialing(this User user, SubscriptionInfo subscriptionInfo) => public static bool IsTrialing(this User user, SubscriptionInfo subscriptionInfo) =>
(subscriptionInfo?.Subscription?.TrialEndDate.HasValue ?? false) && subscriptionInfo != null &&
subscriptionInfo.Subscription.TrialEndDate.Value > DateTime.UtcNow; (subscriptionInfo?.Subscription?.TrialEndDate.HasValue ?? false) &&
subscriptionInfo.Subscription.TrialEndDate.Value > DateTime.UtcNow;
} }

View File

@ -11,10 +11,11 @@ public class OrganizationLicenseClaimsFactory : ILicenseClaimsFactory<Organizati
{ {
public Task<List<Claim>> GenerateClaims(Organization entity, LicenseContext licenseContext) public Task<List<Claim>> GenerateClaims(Organization entity, LicenseContext licenseContext)
{ {
var issued = DateTime.UtcNow;
var subscriptionInfo = licenseContext.SubscriptionInfo; var subscriptionInfo = licenseContext.SubscriptionInfo;
var expires = entity.CalculateFreshExpirationDate(subscriptionInfo); var expires = entity.CalculateFreshExpirationDate(subscriptionInfo, issued);
var refresh = entity.CalculateFreshRefreshDate(subscriptionInfo, expires); var refresh = entity.CalculateFreshRefreshDate(subscriptionInfo, expires, issued);
var expirationWithoutGracePeriod = entity.CalculateFreshExpirationDateWithoutGracePeriod(subscriptionInfo, expires); var expirationWithoutGracePeriod = entity.CalculateFreshExpirationDateWithoutGracePeriod(subscriptionInfo);
var trial = entity.IsTrialing(subscriptionInfo); var trial = entity.IsTrialing(subscriptionInfo);
var claims = new List<Claim> var claims = new List<Claim>
@ -49,12 +50,16 @@ public class OrganizationLicenseClaimsFactory : ILicenseClaimsFactory<Organizati
new(nameof(OrganizationLicenseConstants.Issued), DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)), new(nameof(OrganizationLicenseConstants.Issued), DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)),
new(nameof(OrganizationLicenseConstants.Expires), expires.ToString(CultureInfo.InvariantCulture)), new(nameof(OrganizationLicenseConstants.Expires), expires.ToString(CultureInfo.InvariantCulture)),
new(nameof(OrganizationLicenseConstants.Refresh), refresh.ToString(CultureInfo.InvariantCulture)), new(nameof(OrganizationLicenseConstants.Refresh), refresh.ToString(CultureInfo.InvariantCulture)),
new(nameof(OrganizationLicenseConstants.ExpirationWithoutGracePeriod), expirationWithoutGracePeriod.ToString(CultureInfo.InvariantCulture)),
new(nameof(OrganizationLicenseConstants.Trial), trial.ToString()), new(nameof(OrganizationLicenseConstants.Trial), trial.ToString()),
new(nameof(OrganizationLicenseConstants.UseAdminSponsoredFamilies), entity.UseAdminSponsoredFamilies.ToString()), new(nameof(OrganizationLicenseConstants.UseAdminSponsoredFamilies), entity.UseAdminSponsoredFamilies.ToString()),
new(nameof(OrganizationLicenseConstants.UseOrganizationDomains), entity.UseOrganizationDomains.ToString()), new(nameof(OrganizationLicenseConstants.UseOrganizationDomains), entity.UseOrganizationDomains.ToString()),
}; };
if (expirationWithoutGracePeriod.HasValue)
{
claims.Add(new(nameof(OrganizationLicenseConstants.ExpirationWithoutGracePeriod), expirationWithoutGracePeriod.Value.ToString(CultureInfo.InvariantCulture)));
}
if (entity.Name is not null) if (entity.Name is not null)
{ {
claims.Add(new(nameof(OrganizationLicenseConstants.Name), entity.Name)); claims.Add(new(nameof(OrganizationLicenseConstants.Name), entity.Name));

View File

@ -88,48 +88,10 @@ public class OrganizationLicense : BaseLicense
AllowAdminAccessToAllCollectionItems = org.AllowAdminAccessToAllCollectionItems; AllowAdminAccessToAllCollectionItems = org.AllowAdminAccessToAllCollectionItems;
// //
if (subscriptionInfo?.Subscription == null) Expires = org.CalculateFreshExpirationDate(subscriptionInfo, Issued);
{ Refresh = org.CalculateFreshRefreshDate(subscriptionInfo, Expires, Issued);
if (org.PlanType == PlanType.Custom && org.ExpirationDate.HasValue) ExpirationWithoutGracePeriod = org.CalculateFreshExpirationDateWithoutGracePeriod(subscriptionInfo);
{ Trial = org.IsTrialing(subscriptionInfo);
Expires = Refresh = org.ExpirationDate.Value;
Trial = false;
}
else
{
Expires = Refresh = Issued.AddDays(7);
Trial = true;
}
}
else if (subscriptionInfo.Subscription.TrialEndDate.HasValue &&
subscriptionInfo.Subscription.TrialEndDate.Value > DateTime.UtcNow)
{
Expires = Refresh = subscriptionInfo.Subscription.TrialEndDate.Value;
Trial = true;
}
else
{
if (org.ExpirationDate.HasValue && org.ExpirationDate.Value < DateTime.UtcNow)
{
// expired
Expires = Refresh = org.ExpirationDate.Value;
}
else if (subscriptionInfo?.Subscription?.PeriodDuration != null &&
subscriptionInfo.Subscription.PeriodDuration > TimeSpan.FromDays(180))
{
Refresh = DateTime.UtcNow.AddDays(30);
Expires = subscriptionInfo.Subscription.PeriodEndDate?.AddDays(Constants
.OrganizationSelfHostSubscriptionGracePeriodDays);
ExpirationWithoutGracePeriod = subscriptionInfo.Subscription.PeriodEndDate;
}
else
{
Expires = org.ExpirationDate.HasValue ? org.ExpirationDate.Value.AddMonths(11) : Issued.AddYears(1);
Refresh = DateTime.UtcNow - Expires > TimeSpan.FromDays(30) ? DateTime.UtcNow.AddDays(30) : Expires;
}
Trial = false;
}
UseAdminSponsoredFamilies = org.UseAdminSponsoredFamilies; UseAdminSponsoredFamilies = org.UseAdminSponsoredFamilies;
Hash = Convert.ToBase64String(ComputeHash()); Hash = Convert.ToBase64String(ComputeHash());
@ -247,7 +209,7 @@ public class OrganizationLicense : BaseLicense
private bool ValidLicenseVersion private bool ValidLicenseVersion
{ {
get => Version is >= 1 and <= 16; get => Version is >= 1 and <= CurrentLicenseFileVersion + 1;
} }
public override byte[] GetDataBytes(bool forHash = false) public override byte[] GetDataBytes(bool forHash = false)
@ -569,7 +531,7 @@ public class OrganizationLicense : BaseLicense
* validation. * validation.
*/ */
if (valid && Version >= 16) if (valid && Version >= CurrentLicenseFileVersion + 1)
{ {
valid = organization.UseOrganizationDomains; valid = organization.UseOrganizationDomains;
} }

View File

@ -24,12 +24,9 @@ public class UserLicense : BaseLicense
Premium = user.Premium; Premium = user.Premium;
MaxStorageGb = user.MaxStorageGb; MaxStorageGb = user.MaxStorageGb;
Issued = DateTime.UtcNow; Issued = DateTime.UtcNow;
Expires = subscriptionInfo?.UpcomingInvoice?.Date != null ? Expires = user.CalculateFreshExpirationDate(subscriptionInfo);
subscriptionInfo.UpcomingInvoice.Date.Value.AddDays(7) : Refresh = user.CalculateFreshRefreshDate(subscriptionInfo);
user.PremiumExpirationDate?.AddDays(7); Trial = user.IsTrialing(subscriptionInfo);
Refresh = subscriptionInfo?.UpcomingInvoice?.Date;
Trial = (subscriptionInfo?.Subscription?.TrialEndDate.HasValue ?? false) &&
subscriptionInfo.Subscription.TrialEndDate.Value > DateTime.UtcNow;
Hash = Convert.ToBase64String(ComputeHash()); Hash = Convert.ToBase64String(ComputeHash());
Signature = Convert.ToBase64String(licenseService.SignLicense(this)); Signature = Convert.ToBase64String(licenseService.SignLicense(this));
@ -46,9 +43,9 @@ public class UserLicense : BaseLicense
Premium = user.Premium; Premium = user.Premium;
MaxStorageGb = user.MaxStorageGb; MaxStorageGb = user.MaxStorageGb;
Issued = DateTime.UtcNow; Issued = DateTime.UtcNow;
Expires = user.PremiumExpirationDate?.AddDays(7); Expires = user.CalculateFreshExpirationDate(null);
Refresh = user.PremiumExpirationDate?.Date; Refresh = user.CalculateFreshRefreshDate(null);
Trial = false; Trial = user.IsTrialing(null);
Hash = Convert.ToBase64String(ComputeHash()); Hash = Convert.ToBase64String(ComputeHash());
Signature = Convert.ToBase64String(licenseService.SignLicense(this)); Signature = Convert.ToBase64String(licenseService.SignLicense(this));