Skip to content

Commit d1421d6

Browse files
committed
identity: fix user subscription claim value incorrect for legacy pro users
1 parent 131df3d commit d1421d6

File tree

8 files changed

+40
-127
lines changed

8 files changed

+40
-127
lines changed

Notesnook.API/Controllers/MonographsController.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public async Task<IActionResult> PublishAsync([FromQuery] string? deviceId, [Fro
105105
if (existingMonograph != null && !existingMonograph.Deleted) return await UpdateAsync(deviceId, monograph);
106106

107107
if (monograph.EncryptedContent == null)
108-
monograph.CompressedContent = (await CleanupContentAsync(monograph.Content)).CompressBrotli();
108+
monograph.CompressedContent = (await CleanupContentAsync(User, monograph.Content)).CompressBrotli();
109109
monograph.UserId = userId;
110110
monograph.DatePublished = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
111111

@@ -157,7 +157,7 @@ public async Task<IActionResult> UpdateAsync([FromQuery] string? deviceId, [From
157157
return base.BadRequest("Monograph is too big. Max allowed size is 15mb.");
158158

159159
if (monograph.EncryptedContent == null)
160-
monograph.CompressedContent = (await CleanupContentAsync(monograph.Content)).CompressBrotli();
160+
monograph.CompressedContent = (await CleanupContentAsync(User, monograph.Content)).CompressBrotli();
161161
else
162162
monograph.Content = null;
163163

@@ -309,34 +309,40 @@ private static async Task SendTriggerSyncEventAsync(string userId, string? jti =
309309
});
310310
}
311311

312-
private async Task<string> CleanupContentAsync(string content)
312+
private async Task<string> CleanupContentAsync(ClaimsPrincipal user, string content)
313313
{
314+
if (Constants.IS_SELF_HOSTED) return content;
314315
try
315316
{
316317
var json = JsonSerializer.Deserialize<MonographContent>(content);
317318
var html = json.Data;
318-
if (!Constants.IS_SELF_HOSTED && !User.IsUserSubscribed())
319+
320+
if (user.IsUserSubscribed())
319321
{
320322
var config = Configuration.Default.WithDefaultLoader();
321323
var context = BrowsingContext.New(config);
322324
var document = await context.OpenAsync(r => r.Content(html));
323-
foreach (var element in document.QuerySelectorAll("a,iframe,img,object,svg,button,link"))
325+
foreach (var element in document.QuerySelectorAll("a"))
324326
{
325-
element.Remove();
327+
var href = element.GetAttribute("href");
328+
if (string.IsNullOrEmpty(href)) continue;
329+
if (!await analyzer.IsURLSafeAsync(href))
330+
{
331+
await Slogger<MonographsController>.Info("CleanupContentAsync", "Malicious URL detected: " + href);
332+
element.RemoveAttribute("href");
333+
}
326334
}
327335
html = document.ToHtml();
328336
}
329-
330-
if (User.IsUserSubscribed())
337+
else
331338
{
332339
var config = Configuration.Default.WithDefaultLoader();
333340
var context = BrowsingContext.New(config);
334341
var document = await context.OpenAsync(r => r.Content(html));
335-
foreach (var element in document.QuerySelectorAll("a"))
342+
foreach (var element in document.QuerySelectorAll("a,iframe,img,object,svg,button,link"))
336343
{
337-
var href = element.GetAttribute("href");
338-
if (string.IsNullOrEmpty(href)) continue;
339-
if (!await analyzer.IsURLSafeAsync(href)) element.RemoveAttribute("href");
344+
foreach (var attr in element.Attributes)
345+
element.RemoveAttribute(attr.Name);
340346
}
341347
html = document.ToHtml();
342348
}

Notesnook.API/Extensions/ClaimsPrincipalExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace System.Security.Claims
77
{
88
public static class ClaimsPrincipalExtensions
99
{
10-
private readonly static string[] SUBSCRIBED_CLAIMS = ["believer", "education", "essential", "pro", "premium", "premium_canceled"];
10+
private readonly static string[] SUBSCRIBED_CLAIMS = ["believer", "education", "essential", "pro", "legacy_pro"];
1111
public static bool IsUserSubscribed(this ClaimsPrincipal user)
1212
=> user.Claims.Any((c) => c.Type == "notesnook:status" && SUBSCRIBED_CLAIMS.Contains(c.Value));
1313
}

Streetwriters.Common/Interfaces/IUserSubscriptionService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ public interface IUserSubscriptionService
99
{
1010
[WampProcedure("co.streetwriters.subscriptions.subscriptions.get_user_subscription")]
1111
Task<Subscription> GetUserSubscriptionAsync(string clientId, string userId);
12+
Subscription TransformUserSubscription(Subscription subscription);
1213
}
1314
}

Streetwriters.Identity/Controllers/SignupController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public async Task<IActionResult> Signup([FromForm] SignupForm form)
109109
await UserManager.AddToRoleAsync(user, client.Id);
110110
if (Constants.IS_SELF_HOSTED)
111111
{
112-
await UserManager.AddClaimAsync(user, UserService.SubscriptionPlanToClaim(client.Id, SubscriptionPlan.BELIEVER));
112+
await UserManager.AddClaimAsync(user, new Claim(UserService.GetClaimKey(client.Id), "believer"));
113113
}
114114
else
115115
{

Streetwriters.Identity/MessageHandlers/CreateSubscription.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,19 @@ namespace Streetwriters.Identity.MessageHandlers
3030
{
3131
public class CreateSubscription
3232
{
33-
public static async Task Process(CreateSubscriptionMessage message, UserManager<User> userManager)
33+
public static async Task Process(Subscription subscription, UserManager<User> userManager)
3434
{
35-
var user = await userManager.FindByIdAsync(message.UserId);
36-
var client = Clients.FindClientByAppId(message.AppId);
35+
var user = await userManager.FindByIdAsync(subscription.UserId);
36+
var client = Clients.FindClientByAppId(subscription.AppId);
3737
if (client == null || user == null) return;
3838

3939
IdentityUserClaim<string> statusClaim = user.Claims.FirstOrDefault((c) => c.ClaimType == UserService.GetClaimKey(client.Id));
40-
Claim subscriptionClaim = UserService.SubscriptionTypeToClaim(client.Id, message.Type);
40+
Claim subscriptionClaim = UserService.SubscriptionPlanToClaim(client.Id, subscription);
4141
if (statusClaim?.ClaimValue == subscriptionClaim.Value) return;
4242
if (statusClaim != null)
4343
await userManager.ReplaceClaimAsync(user, statusClaim.ToClaim(), subscriptionClaim);
44-
// we no longer accept legacy subscriptions.
45-
// else
46-
// await userManager.AddClaimAsync(user, subscriptionClaim);
44+
else
45+
await userManager.AddClaimAsync(user, subscriptionClaim);
4746
}
4847

4948
}

Streetwriters.Identity/MessageHandlers/CreateSubscriptionV2.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.

Streetwriters.Identity/Services/UserService.cs

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ You should have received a copy of the Affero GNU General Public License
1717
along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
*/
1919

20+
using System;
2021
using System.Linq;
2122
using System.Security.Claims;
2223
using System.Threading.Tasks;
@@ -28,27 +29,6 @@ namespace Streetwriters.Identity.Services
2829
{
2930
public class UserService
3031
{
31-
private static SubscriptionType? GetUserSubscriptionStatus(string clientId, User user)
32-
{
33-
var claimKey = GetClaimKey(clientId);
34-
var status = user.Claims.FirstOrDefault((c) => c.ClaimType == claimKey).ClaimValue;
35-
switch (status)
36-
{
37-
case "basic":
38-
return SubscriptionType.BASIC;
39-
case "trial":
40-
return SubscriptionType.TRIAL;
41-
case "premium":
42-
return SubscriptionType.PREMIUM;
43-
case "premium_canceled":
44-
return SubscriptionType.PREMIUM_CANCELED;
45-
case "premium_expired":
46-
return SubscriptionType.PREMIUM_EXPIRED;
47-
default:
48-
return null;
49-
}
50-
}
51-
5232
private static SubscriptionPlan? GetUserSubscriptionPlan(string clientId, User user)
5333
{
5434
var claimKey = GetClaimKey(clientId);
@@ -72,39 +52,23 @@ public class UserService
7252

7353
public static bool IsSMSMFAAllowed(string clientId, User user)
7454
{
75-
var legacyStatus = GetUserSubscriptionStatus(clientId, user);
7655
var status = GetUserSubscriptionPlan(clientId, user);
77-
if (legacyStatus == null && status == null) return false;
78-
return legacyStatus == SubscriptionType.PREMIUM ||
79-
legacyStatus == SubscriptionType.PREMIUM_CANCELED ||
56+
if (status == null) return false;
57+
return status == SubscriptionPlan.LEGACY_PRO ||
8058
status == SubscriptionPlan.PRO ||
8159
status == SubscriptionPlan.EDUCATION ||
8260
status == SubscriptionPlan.BELIEVER;
8361
}
8462

85-
public static Claim SubscriptionTypeToClaim(string clientId, SubscriptionType type)
63+
public static Claim SubscriptionPlanToClaim(string clientId, Subscription subscription)
8664
{
8765
var claimKey = GetClaimKey(clientId);
88-
switch (type)
89-
{
90-
case SubscriptionType.BASIC:
91-
return new Claim(claimKey, "basic");
92-
case SubscriptionType.TRIAL:
93-
return new Claim(claimKey, "trial");
94-
case SubscriptionType.PREMIUM:
95-
return new Claim(claimKey, "premium");
96-
case SubscriptionType.PREMIUM_CANCELED:
97-
return new Claim(claimKey, "premium_canceled");
98-
case SubscriptionType.PREMIUM_EXPIRED:
99-
return new Claim(claimKey, "premium_expired");
100-
}
101-
return null;
102-
}
10366

104-
public static Claim SubscriptionPlanToClaim(string clientId, SubscriptionPlan plan)
105-
{
106-
var claimKey = GetClaimKey(clientId);
107-
switch (plan)
67+
// just in case
68+
if (subscription.ExpiryDate <= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
69+
return new Claim(claimKey, "free");
70+
71+
switch (subscription.Plan)
10872
{
10973
case SubscriptionPlan.FREE:
11074
return new Claim(claimKey, "free");
@@ -116,6 +80,8 @@ public static Claim SubscriptionPlanToClaim(string clientId, SubscriptionPlan pl
11680
return new Claim(claimKey, "essential");
11781
case SubscriptionPlan.PRO:
11882
return new Claim(claimKey, "pro");
83+
case SubscriptionPlan.LEGACY_PRO:
84+
return new Claim(claimKey, "legacy_pro");
11985
}
12086
return null;
12187
}

Streetwriters.Identity/Startup.cs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -235,26 +235,16 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
235235
{
236236
realm.Services.RegisterCallee(() => app.ApplicationServices.CreateScope().ServiceProvider.GetRequiredService<IUserAccountService>());
237237

238-
realm.Subscribe(SubscriptionServerTopics.CreateSubscriptionTopic, async (CreateSubscriptionMessage message) =>
238+
realm.Subscribe(SubscriptionServerTopics.CreateSubscriptionTopic, async (Subscription subscription) =>
239239
{
240240
using (var serviceScope = app.ApplicationServices.CreateScope())
241241
{
242242
var services = serviceScope.ServiceProvider;
243243
var userManager = services.GetRequiredService<UserManager<User>>();
244-
await MessageHandlers.CreateSubscription.Process(message, userManager);
244+
await MessageHandlers.CreateSubscription.Process(subscription, userManager);
245245
}
246246
});
247247

248-
realm.Subscribe(SubscriptionServerTopics.CreateSubscriptionV2Topic, async (CreateSubscriptionMessageV2 message) =>
249-
{
250-
using (var serviceScope = app.ApplicationServices.CreateScope())
251-
{
252-
var services = serviceScope.ServiceProvider;
253-
var userManager = services.GetRequiredService<UserManager<User>>();
254-
await MessageHandlers.CreateSubscriptionV2.Process(message, userManager);
255-
}
256-
});
257-
258248
realm.Subscribe(SubscriptionServerTopics.DeleteSubscriptionTopic, async (DeleteSubscriptionMessage message) =>
259249
{
260250
using (var serviceScope = app.ApplicationServices.CreateScope())

0 commit comments

Comments
 (0)