1- using Bit . Core . Billing . Constants ;
1+ using System . Security . Claims ;
2+ using Bit . Core . Billing . Constants ;
3+ using Bit . Core . Billing . Licenses ;
4+ using Bit . Core . Billing . Licenses . Extensions ;
5+ using Bit . Core . Billing . Models . Business ;
26using Bit . Core . Entities ;
37using Bit . Core . Models . Api ;
48using Bit . Core . Models . Business ;
@@ -41,6 +45,51 @@ public SubscriptionResponseModel(User user)
4145 MaxStorageGb = user . MaxStorageGb ;
4246 }
4347
48+ /// <summary>
49+ /// BACKWARD COMPATIBILITY CONSTRUCTOR
50+ /// This constructor is used when the PM24996ImplementUpgradeFromFreeDialog feature flag is NOT enabled.
51+ /// When the feature flag is enabled, clients should use the new separate /license endpoint.
52+ /// </summary>
53+ /// <param name="user">The user entity containing storage and premium subscription information</param>
54+ /// <param name="subscription">Subscription information retrieved from the payment provider (Stripe/Braintree)</param>
55+ /// <param name="license">The user's license containing expiration and feature entitlements</param>
56+ /// <param name="claimsPrincipal">The claims principal containing cryptographically secure token claims</param>
57+ /// <param name="includeMilestone2Discount">
58+ /// Whether to include discount information in the response.
59+ /// Set to true when the PM23341_Milestone_2 feature flag is enabled AND
60+ /// you want to expose Milestone 2 discount information to the client.
61+ /// The discount will only be included if it matches the specific Milestone 2 coupon ID.
62+ /// </param>
63+ public SubscriptionResponseModel ( User user , SubscriptionInfo ? subscription , UserLicense license , ClaimsPrincipal ? claimsPrincipal , bool includeMilestone2Discount = false )
64+ : base ( "subscription" )
65+ {
66+ Subscription = subscription ? . Subscription != null ? new BillingSubscription ( subscription . Subscription ) : null ;
67+ UpcomingInvoice = subscription ? . UpcomingInvoice != null ?
68+ new BillingSubscriptionUpcomingInvoice ( subscription . UpcomingInvoice ) : null ;
69+ StorageName = user . Storage . HasValue ? CoreHelpers . ReadableBytesSize ( user . Storage . Value ) : null ;
70+ StorageGb = user . Storage . HasValue ? Math . Round ( user . Storage . Value / 1073741824D , 2 ) : 0 ; // 1 GB
71+ MaxStorageGb = user . MaxStorageGb ;
72+ License = license ;
73+
74+ // CRITICAL: When a license has a Token (JWT), ALWAYS use the expiration from the token claim
75+ // The token's expiration is cryptographically secured and cannot be tampered with
76+ // The file's Expires property can be manually edited and should NOT be trusted for display
77+ if ( claimsPrincipal != null )
78+ {
79+ Expiration = claimsPrincipal . GetValue < DateTime ? > ( UserLicenseConstants . Expires ) ;
80+ }
81+ else
82+ {
83+ // No token - use the license file expiration (for older licenses without tokens)
84+ Expiration = license . Expires ;
85+ }
86+
87+ // Only display the Milestone 2 subscription discount on the subscription page.
88+ CustomerDiscount = ShouldIncludeMilestone2Discount ( includeMilestone2Discount , subscription ? . CustomerDiscount )
89+ ? new BillingCustomerDiscount ( subscription ! . CustomerDiscount ! )
90+ : null ;
91+ }
92+
4493 public string ? StorageName { get ; set ; }
4594 public double ? StorageGb { get ; set ; }
4695 public short ? MaxStorageGb { get ; set ; }
@@ -61,6 +110,24 @@ public SubscriptionResponseModel(User user)
61110 /// </summary>
62111 public BillingCustomerDiscount ? CustomerDiscount { get ; set ; }
63112
113+ /// <summary>
114+ /// BACKWARD COMPATIBILITY PROPERTY
115+ /// The user's license containing feature entitlements and metadata.
116+ /// Only populated when the PM24996ImplementUpgradeFromFreeDialog feature flag is NOT enabled.
117+ /// When the feature flag is enabled, clients should use the separate /license endpoint.
118+ /// </summary>
119+ public UserLicense ? License { get ; set ; }
120+
121+ /// <summary>
122+ /// BACKWARD COMPATIBILITY PROPERTY
123+ /// The license expiration date.
124+ /// Extracted from the cryptographically secured JWT token when available,
125+ /// otherwise falls back to the license file's expiration date.
126+ /// Only populated when the PM24996ImplementUpgradeFromFreeDialog feature flag is NOT enabled.
127+ /// When the feature flag is enabled, clients should use the separate /license endpoint.
128+ /// </summary>
129+ public DateTime ? Expiration { get ; set ; }
130+
64131 /// <summary>
65132 /// Determines whether the Milestone 2 discount should be included in the response.
66133 /// </summary>
0 commit comments