mirror of
https://github.com/streetwriters/notesnook-sync-server.git
synced 2026-10-01 10:49:33 +02:00
api: improve pro authorization handling
This commit is contained in:
1 parent
690414cb51
commit
cb0ad7ac9a
3 files changed
+35
-13
No files matched your search
@@ -17,21 +17,47 @@ You should have received a copy of the Affero GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Notesnook.API.Authorization
|
namespace Notesnook.API.Authorization
|
||||||
{
|
{
|
||||||
public class ProUserRequirement : AuthorizationHandler<ProUserRequirement>, IAuthorizationRequirement
|
public class ProUserRequirement : AuthorizationHandler<ProUserRequirement>, IAuthorizationRequirement
|
||||||
{
|
{
|
||||||
private readonly string[] allowedClaims = { "trial", "premium", "premium_canceled" };
|
private readonly Dictionary<string, string> pathErrorPhraseMap = new()
|
||||||
|
{
|
||||||
|
["/s3"] = "upload attachments",
|
||||||
|
["/s3/multipart"] = "upload attachments",
|
||||||
|
};
|
||||||
|
private readonly string[] allowedClaims = ["trial", "premium", "premium_canceled"];
|
||||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ProUserRequirement requirement)
|
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ProUserRequirement requirement)
|
||||||
{
|
{
|
||||||
var isProOrTrial = context.User.HasClaim((c) => c.Type == "notesnook:status" && allowedClaims.Contains(c.Value));
|
PathString path = context.Resource is DefaultHttpContext httpContext ? httpContext.Request.Path : null;
|
||||||
if (isProOrTrial)
|
var isProOrTrial = context.User.Claims.Any((c) => c.Type == "notesnook:status" && allowedClaims.Contains(c.Value));
|
||||||
context.Succeed(requirement);
|
if (isProOrTrial) context.Succeed(requirement);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var phrase = "continue";
|
||||||
|
foreach (var item in pathErrorPhraseMap)
|
||||||
|
{
|
||||||
|
if (path != null && path.StartsWithSegments(item.Key))
|
||||||
|
phrase = item.Value;
|
||||||
|
}
|
||||||
|
var error = $"Please upgrade to Pro to {phrase}.";
|
||||||
|
context.Fail(new AuthorizationFailureReason(this, error));
|
||||||
|
}
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Task HandleAsync(AuthorizationHandlerContext context)
|
||||||
|
{
|
||||||
|
return this.HandleRequirementAsync(context, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ namespace Notesnook.API.Authorization
|
|||||||
{
|
{
|
||||||
public class SyncRequirement : AuthorizationHandler<SyncRequirement>, IAuthorizationRequirement
|
public class SyncRequirement : AuthorizationHandler<SyncRequirement>, IAuthorizationRequirement
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, string> pathErrorPhraseMap = new Dictionary<string, string>
|
private readonly Dictionary<string, string> pathErrorPhraseMap = new()
|
||||||
{
|
{
|
||||||
["/sync/attachments"] = "use attachments",
|
["/sync/attachments"] = "use attachments",
|
||||||
["/sync"] = "sync your notes",
|
["/sync"] = "sync your notes",
|
||||||
@@ -43,13 +43,9 @@ namespace Notesnook.API.Authorization
|
|||||||
PathString path = context.Resource is DefaultHttpContext httpContext ? httpContext.Request.Path : null;
|
PathString path = context.Resource is DefaultHttpContext httpContext ? httpContext.Request.Path : null;
|
||||||
var result = this.IsAuthorized(context.User, path);
|
var result = this.IsAuthorized(context.User, path);
|
||||||
if (result.Succeeded) context.Succeed(requirement);
|
if (result.Succeeded) context.Succeed(requirement);
|
||||||
else
|
else if (result.AuthorizationFailure.FailureReasons.Any())
|
||||||
{
|
context.Fail(result.AuthorizationFailure.FailureReasons.First());
|
||||||
var hasReason = result.AuthorizationFailure.FailureReasons.Any();
|
else context.Fail();
|
||||||
if (hasReason)
|
|
||||||
context.Fail(result.AuthorizationFailure.FailureReasons.First());
|
|
||||||
else context.Fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace Notesnook.API.Extensions
|
|||||||
{
|
{
|
||||||
var error = string.Join("\n", policyAuthorizationResult.AuthorizationFailure.FailureReasons.Select((r) => r.Message));
|
var error = string.Join("\n", policyAuthorizationResult.AuthorizationFailure.FailureReasons.Select((r) => r.Message));
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(error) && !isWebsocket)
|
if (!string.IsNullOrEmpty(error))
|
||||||
{
|
{
|
||||||
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
httpContext.Response.ContentType = "application/json";
|
httpContext.Response.ContentType = "application/json";
|
||||||
|
|||||||
Reference in new issue
Block a user