< Summary

Information
Class: Api.Auth.Handlers.PermissionCheckAuthorizationHandler
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Auth/Handlers/PermissionCheckAuthorizationHandler.cs
Line coverage
94%
Covered lines: 17
Uncovered lines: 1
Coverable lines: 18
Total lines: 95
Line coverage: 94.4%
Branch coverage
83%
Covered branches: 5
Total branches: 6
Branch coverage: 83.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
HandleRequirementAsync(...)83.33%6694.44%

File(s)

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

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <[email protected]>
 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)
 19    : 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)
 25    {
 26        if (
 27            policyName.StartsWith(POLICY_PREFIX)
 28            && long.TryParse(policyName[POLICY_PREFIX.Length..], out long permissionBits)
 29        )
 30        {
 31            return Task.FromResult<AuthorizationPolicy?>(
 32                new AuthorizationPolicyBuilder()
 33                    .AddRequirements(
 34                        new PermissionCheckRequirement((UserPermissionBits)permissionBits)
 35                    )
 36                    .Build()
 37            );
 38        }
 39
 40        if (policyName == RemoteServicePolicyName)
 41        {
 42            return Task.FromResult<AuthorizationPolicy?>(
 43                new AuthorizationPolicyBuilder()
 44                    .RequireClaim(RemoteServiceToken.ServiceIdentifierType)
 45                    .Build()
 46            );
 47        }
 48
 49        return base.GetPolicyAsync(policyName);
 50    }
 51}
 52
 53class PermissionCheckAuthorizationHandler
 54    : AuthorizationHandler<PermissionCheckRequirement>
 55{
 56    protected override Task HandleRequirementAsync(
 57        AuthorizationHandlerContext context,
 58        PermissionCheckRequirement requirement
 59    )
 160    {
 161        var userPermissionBitsString = context.User.FindFirstValue(
 162            UserTokenEF.PermissionBitsType
 163        );
 64
 165        if (userPermissionBitsString is null)
 166            return Task.CompletedTask;
 67
 168        if (!long.TryParse(userPermissionBitsString, out long userPermissionBitsLong))
 069            return Task.CompletedTask;
 70
 171        var userPermissionBits = (UserPermissionBits)userPermissionBitsLong;
 72
 173        if (
 174            (requirement.PermissionBits & userPermissionBits)
 175            == requirement.PermissionBits
 176        )
 177        {
 178            context.Succeed(requirement);
 179        }
 180        return Task.CompletedTask;
 181    }
 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}