feat: pivot to social media workflow app
Some checks failed
Backend CI/CD / build_and_deploy (push) Has been cancelled
Frontend CI/CD / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-04-24 12:58:35 -04:00
parent 0f4acc1b6d
commit df3e602015
349 changed files with 18685 additions and 16010 deletions

View File

@@ -0,0 +1,56 @@
using System.Security.Claims;
using Socialize.Modules.Identity.Contracts;
namespace Socialize.Infrastructure.Security;
public sealed class AccessScopeService
{
public bool IsManager(ClaimsPrincipal user)
{
return user.IsInRole(KnownRoles.Administrator) || user.IsInRole(KnownRoles.Manager);
}
public bool IsProvider(ClaimsPrincipal user)
{
return user.IsInRole(KnownRoles.Provider);
}
public bool IsClient(ClaimsPrincipal user)
{
return user.IsInRole(KnownRoles.Client);
}
public bool CanAccessWorkspace(ClaimsPrincipal user, Guid workspaceId)
{
return IsManager(user) || user.GetWorkspaceScopeIds().Contains(workspaceId);
}
public bool CanManageWorkspace(ClaimsPrincipal user, Guid workspaceId)
{
return IsManager(user) && CanAccessWorkspace(user, workspaceId);
}
public bool CanAccessClient(ClaimsPrincipal user, Guid workspaceId, Guid clientId)
{
return IsManager(user)
|| (CanAccessWorkspace(user, workspaceId) && user.GetClientScopeIds().Contains(clientId));
}
public bool CanAccessProject(ClaimsPrincipal user, Guid workspaceId, Guid clientId, Guid projectId)
{
return IsManager(user)
|| (CanAccessClient(user, workspaceId, clientId) && user.GetProjectScopeIds().Contains(projectId));
}
public bool CanContributeToProject(ClaimsPrincipal user, Guid workspaceId, Guid clientId, Guid projectId)
{
return IsManager(user) || (IsProvider(user) && CanAccessProject(user, workspaceId, clientId, projectId));
}
public bool CanReviewContent(ClaimsPrincipal user, Guid workspaceId, Guid clientId, Guid projectId)
{
return IsManager(user)
|| IsProvider(user) && CanAccessProject(user, workspaceId, clientId, projectId)
|| IsClient(user) && CanAccessClient(user, workspaceId, clientId);
}
}

View File

@@ -1,9 +1,38 @@
using System.Security.Claims;
namespace Hutopy.Infrastructure.Security;
namespace Socialize.Infrastructure.Security;
public static class ClaimsPrincipalExtensions
{
public static IReadOnlyCollection<Guid> GetScopeIds(this ClaimsPrincipal claims, string key)
{
return claims.FindAll(key)
.Select(claim => Guid.TryParse(claim.Value, out Guid value) ? value : Guid.Empty)
.Where(value => value != Guid.Empty)
.Distinct()
.ToArray();
}
public static IReadOnlyCollection<Guid> GetWorkspaceScopeIds(this ClaimsPrincipal claims)
{
return claims.GetScopeIds(KnownClaims.WorkspaceScope);
}
public static IReadOnlyCollection<Guid> GetClientScopeIds(this ClaimsPrincipal claims)
{
return claims.GetScopeIds(KnownClaims.ClientScope);
}
public static IReadOnlyCollection<Guid> GetProjectScopeIds(this ClaimsPrincipal claims)
{
return claims.GetScopeIds(KnownClaims.ProjectScope);
}
public static string? GetPersona(this ClaimsPrincipal claims)
{
return (string?)claims.GetClaim<string?>(KnownClaims.Persona);
}
public static Guid GetUserId(this ClaimsPrincipal claims)
{
return (Guid)claims.GetRequiredClaim<Guid>(ClaimTypes.NameIdentifier);

View File

@@ -3,7 +3,7 @@ using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
namespace Hutopy.Infrastructure.Security;
namespace Socialize.Infrastructure.Security;
public static class JwtTokenHelper
{
@@ -17,7 +17,9 @@ public static class JwtTokenHelper
string? alias,
string firstname,
string lastname,
string? portraitUrl)
string? portraitUrl,
IEnumerable<string> roles,
IEnumerable<Claim> additionalClaims)
{
SymmetricSecurityKey securityKey = new(Encoding.UTF8.GetBytes(key));
SigningCredentials credentials = new(securityKey, SecurityAlgorithms.HmacSha256);
@@ -40,6 +42,18 @@ public static class JwtTokenHelper
claims.Add(new Claim(KnownClaims.PortraitUrl, portraitUrl));
}
foreach (string role in roles.Distinct(StringComparer.Ordinal))
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
foreach (Claim claim in additionalClaims
.Where(claim => !string.IsNullOrWhiteSpace(claim.Type) && !string.IsNullOrWhiteSpace(claim.Value))
.DistinctBy(claim => $"{claim.Type}:{claim.Value}"))
{
claims.Add(claim);
}
JwtSecurityToken token = new(
issuer,
audience,

View File

@@ -1,7 +1,11 @@
namespace Hutopy.Infrastructure.Security;
namespace Socialize.Infrastructure.Security;
public static class KnownClaims
{
public const string Alias = "alias";
public const string PortraitUrl = "portraitUrl";
public const string WorkspaceScope = "workspace";
public const string ClientScope = "client";
public const string ProjectScope = "project";
public const string Persona = "persona";
}

View File

@@ -1,4 +1,4 @@
namespace Hutopy.Infrastructure.Security;
namespace Socialize.Infrastructure.Security;
public class MissingClaimException(
string claimName)

View File

@@ -1,7 +1,7 @@
using System.Security.Cryptography;
using System.Text;
namespace Hutopy.Infrastructure.Security;
namespace Socialize.Infrastructure.Security;
// If we need to add special characters we can alternate between 2 pools.
public static class PasswordGenerator

View File

@@ -1,6 +1,6 @@
using System.Security.Cryptography;
namespace Hutopy.Infrastructure.Security;
namespace Socialize.Infrastructure.Security;
public static class RefreshTokenGenerator
{