< Summary

Information
Class: Api.Auth.Handlers.PermissionPolicyProvider
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Auth/Handlers/PermissionCheckAuthorizationHandler.cs
Line coverage
65%
Covered lines: 15
Uncovered lines: 8
Coverable lines: 23
Total lines: 95
Line coverage: 65.2%
Branch coverage
33%
Covered branches: 2
Total branches: 6
Branch coverage: 33.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetPolicyAsync(...)33.33%8663.64%

File(s)

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Auth/Handlers/PermissionCheckAuthorizationHandler.cs

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <alper@alper-celik.dev>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5using System.Security.Claims;
 6using Api.Auth.Models;
 7using Microsoft.AspNetCore.Authorization;
 8using Microsoft.Extensions.Options;
 9
 10namespace Api.Auth.Handlers;
 11
 12public class PermissionCheckRequirement(UserPermissionBits permissionBits)
 13    : IAuthorizationRequirement
 14{
 15    public UserPermissionBits PermissionBits { get; } = permissionBits;
 16}
 17
 18public class PermissionPolicyProvider(IOptions<AuthorizationOptions> options)
 119    : DefaultAuthorizationPolicyProvider(options)
 20{
 21    public const string POLICY_PREFIX = "PermissionBits_";
 22    public const string RemoteServicePolicyName = "RemoteService";
 23
 24    public override Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
 125    {
 126        if (
 127            policyName.StartsWith(POLICY_PREFIX)
 128            && long.TryParse(policyName[POLICY_PREFIX.Length..], out long permissionBits)
 129        )
 130        {
 131            return Task.FromResult<AuthorizationPolicy?>(
 132                new AuthorizationPolicyBuilder()
 133                    .AddRequirements(
 134                        new PermissionCheckRequirement((UserPermissionBits)permissionBits)
 135                    )
 136                    .Build()
 137            );
 38        }
 39
 040        if (policyName == RemoteServicePolicyName)
 041        {
 042            return Task.FromResult<AuthorizationPolicy?>(
 043                new AuthorizationPolicyBuilder()
 044                    .RequireClaim(RemoteServiceToken.ServiceIdentifierType)
 045                    .Build()
 046            );
 47        }
 48
 049        return base.GetPolicyAsync(policyName);
 150    }
 51}
 52
 53class PermissionCheckAuthorizationHandler
 54    : AuthorizationHandler<PermissionCheckRequirement>
 55{
 56    protected override Task HandleRequirementAsync(
 57        AuthorizationHandlerContext context,
 58        PermissionCheckRequirement requirement
 59    )
 60    {
 61        var userPermissionBitsString = context.User.FindFirstValue(
 62            UserTokenEF.PermissionBitsType
 63        );
 64
 65        if (userPermissionBitsString is null)
 66            return Task.CompletedTask;
 67
 68        if (!long.TryParse(userPermissionBitsString, out long userPermissionBitsLong))
 69            return Task.CompletedTask;
 70
 71        var userPermissionBits = (UserPermissionBits)userPermissionBitsLong;
 72
 73        if (
 74            (requirement.PermissionBits & userPermissionBits)
 75            == requirement.PermissionBits
 76        )
 77        {
 78            context.Succeed(requirement);
 79        }
 80        return Task.CompletedTask;
 81    }
 82}
 83
 84class PermissionCheckAuthorizeAttribute
 85    : HotChocolate.Authorization.AuthorizeAttribute,
 86        IAuthorizeData
 87{
 88    public PermissionCheckAuthorizeAttribute(UserPermissionBits permissionBits)
 89    {
 90        Policy = $"{PermissionPolicyProvider.POLICY_PREFIX}{(long)permissionBits}";
 91    }
 92
 93    public string? AuthenticationSchemes { get; set; }
 94    string? IAuthorizeData.Roles { get; set; }
 95}