From 8c116af2a031c4167a0e41e28fcad613442e660a Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 2 Mar 2025 12:51:02 +0100 Subject: [PATCH] init --- .gitignore | 5 + .../.idea.W542.GandalfReborn/.idea/.gitignore | 13 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + .../.idea/dataSources.xml | 13 + .../.idea/indexLayout.xml | 11 + .idea/.idea.W542.GandalfReborn/.idea/vcs.xml | 6 + Abstractions/Abstractions.csproj | 9 + Abstractions/Invoker.cs | 47 ++ Abstractions/InvokerContext.cs | 6 + Api/Api.csproj | 31 + Api/Commands/AuthCodeRequestCommand.cs | 18 + Api/Commands/CreateAuthCodeCommand.cs | 11 + Api/Commands/CreateTokensCommand.cs | 9 + Api/Commands/HashPasswordCommand.cs | 8 + Api/Commands/IGrCommand.cs | 5 + Api/Commands/RegisterCommand.cs | 11 + Api/Controllers/AuthController.cs | 31 + Api/Extensions/ResultExtentions.cs | 37 + Api/Handlers/Commands/IGrCommandHandler.cs | 6 + .../Commands/RegisterCommandHandler.cs | 48 ++ .../Security/AuthCodeRequestCommandHandler.cs | 69 ++ .../Security/CreateAuthCodeCommandHandler.cs | 38 + .../Security/CreateTokensCommandHandler.cs | 79 ++ .../Security/GetTokensCommandHandler.cs | 57 ++ .../Security/PasswordHashingHandler.cs | 26 + Api/Program.cs | 76 ++ Api/Properties/launchSettings.json | 41 + Api/TestController.cs | 105 +++ Api/appsettings.Development.json | 14 + Api/appsettings.json | 9 + Core/Core.csproj | 20 + Data/Data.csproj | 28 + Data/Database/ApplicationContext.cs | 206 +++++ Data/Database/CoreContext.cs | 208 +++++ Data/Database/GrDbConnectionInterceptor.cs | 23 + .../Repositories/AuthCodeRepository.cs | 14 + Data/Database/Repositories/GrRepository.cs | 112 +++ Data/Database/Repositories/IGrRepository.cs | 18 + .../Repositories/SubjectRepository.cs | 9 + .../Repositories/TokenMetadataRepository.cs | 8 + Data/Dto/AuthCodeDto.cs | 8 + Data/Dto/TokenDto.cs | 7 + Data/Entities/App/AppRelationEntity.cs | 26 + Data/Entities/App/AppSubjectRelationEntity.cs | 29 + Data/Entities/Base/EntityVisibility.cs | 9 + Data/Entities/Base/IEntity.cs | 6 + Data/Entities/Base/IMappingEntity.cs | 3 + Data/Entities/Base/IdData.cs | 6 + Data/Entities/Base/SubjectData.cs | 6 + Data/Entities/Base/TenantRelationData.cs | 6 + Data/Entities/Base/VisibilityData.cs | 6 + Data/Entities/ContentKeyAttribute.cs | 6 + ...RelationInternalAuthorityRelationEntity.cs | 29 + Data/Entities/Security/AuthCodeEntity.cs | 13 + Data/Entities/Security/AuthorityEntity.cs | 27 + Data/Entities/Security/AuthorityType.cs | 7 + ...RelationInternalAuthorityRelationEntity.cs | 28 + Data/Entities/Security/TokenMetaDataEntity.cs | 14 + Data/Entities/Security/TokenType.cs | 7 + Data/Entities/Subject/SignIn/SignInEntity.cs | 12 + Data/Entities/Subject/SignIn/SignInMethod.cs | 8 + Data/Entities/Subject/SubjectEntity.cs | 14 + Data/Entities/Tenant/OwnerData.cs | 8 + Data/Entities/Tenant/TenantEntity.cs | 28 + .../Tenant/TenantSubjectRelationEntity.cs | 28 + Data/Entities/Version/IVersionEntity.cs | 18 + Data/Entities/Version/VersionAction.cs | 9 + Data/Extensions/StringExtensions.cs | 37 + Data/Mapper/AuthCodeDtoMappingProfile.cs | 13 + .../Migrations/20240903154112_sus.Designer.cs | 663 ++++++++++++++++ Data/Migrations/20240903154112_sus.cs | 592 ++++++++++++++ .../20240914003536_addTokens.Designer.cs | 716 +++++++++++++++++ Data/Migrations/20240914003536_addTokens.cs | 62 ++ .../20240914005530_affwaf.Designer.cs | 716 +++++++++++++++++ Data/Migrations/20240914005530_affwaf.cs | 173 +++++ .../20240914012943_fawfghh.Designer.cs | 716 +++++++++++++++++ Data/Migrations/20240914012943_fawfghh.cs | 173 +++++ .../20240914014850_gjjjjjj.Designer.cs | 716 +++++++++++++++++ Data/Migrations/20240914014850_gjjjjjj.cs | 22 + .../20240914224344_jsoikgsoieg.Designer.cs | 719 +++++++++++++++++ Data/Migrations/20240914224344_jsoikgsoieg.cs | 30 + .../20240919005908_afwawfawf.Designer.cs | 730 ++++++++++++++++++ Data/Migrations/20240919005908_afwawfawf.cs | 35 + .../20240919010339_ffffff.Designer.cs | 729 +++++++++++++++++ Data/Migrations/20240919010339_ffffff.cs | 29 + .../20240919010748_jm├ñpromh.Designer.cs | 730 ++++++++++++++++++ Data/Migrations/20240919010748_jm├ñpromh.cs | 29 + .../20240919012025_fghdhhzttr.Designer.cs | 719 +++++++++++++++++ Data/Migrations/20240919012025_fghdhhzttr.cs | 35 + .../20240921214234_kl├╢hmpdmpmgr.Designer.cs | 726 +++++++++++++++++ .../20240921214234_kl├╢hmpdmpmgr.cs | 44 ++ .../ApplicationContextModelSnapshot.cs | 723 +++++++++++++++++ Docker/docker-compose.yml | 13 + Scripts/add-migration.cmd | 3 + Scripts/reset-database.cmd | 3 + Scripts/update-database.cmd | 2 + Security/GrAuthorizeAttribute.cs | 62 ++ .../GandalfRebornJwtTokenAuthExtensions.cs | 14 + .../GandalfRebornJwtTokenAuthSchemeHandler.cs | 157 ++++ .../GandalfRebornJwtTokenAuthSchemeOptions.cs | 9 + Security/Security.csproj | 20 + Service/Service.csproj | 13 + W542.GandalfReborn.sln | 34 + 103 files changed, 12065 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.idea.W542.GandalfReborn/.idea/.gitignore create mode 100644 .idea/.idea.W542.GandalfReborn/.idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/.idea.W542.GandalfReborn/.idea/dataSources.xml create mode 100644 .idea/.idea.W542.GandalfReborn/.idea/indexLayout.xml create mode 100644 .idea/.idea.W542.GandalfReborn/.idea/vcs.xml create mode 100644 Abstractions/Abstractions.csproj create mode 100644 Abstractions/Invoker.cs create mode 100644 Abstractions/InvokerContext.cs create mode 100644 Api/Api.csproj create mode 100644 Api/Commands/AuthCodeRequestCommand.cs create mode 100644 Api/Commands/CreateAuthCodeCommand.cs create mode 100644 Api/Commands/CreateTokensCommand.cs create mode 100644 Api/Commands/HashPasswordCommand.cs create mode 100644 Api/Commands/IGrCommand.cs create mode 100644 Api/Commands/RegisterCommand.cs create mode 100644 Api/Controllers/AuthController.cs create mode 100644 Api/Extensions/ResultExtentions.cs create mode 100644 Api/Handlers/Commands/IGrCommandHandler.cs create mode 100644 Api/Handlers/Commands/RegisterCommandHandler.cs create mode 100644 Api/Handlers/Security/AuthCodeRequestCommandHandler.cs create mode 100644 Api/Handlers/Security/CreateAuthCodeCommandHandler.cs create mode 100644 Api/Handlers/Security/CreateTokensCommandHandler.cs create mode 100644 Api/Handlers/Security/GetTokensCommandHandler.cs create mode 100644 Api/Handlers/Security/PasswordHashingHandler.cs create mode 100644 Api/Program.cs create mode 100644 Api/Properties/launchSettings.json create mode 100644 Api/TestController.cs create mode 100644 Api/appsettings.Development.json create mode 100644 Api/appsettings.json create mode 100644 Core/Core.csproj create mode 100644 Data/Data.csproj create mode 100644 Data/Database/ApplicationContext.cs create mode 100644 Data/Database/CoreContext.cs create mode 100644 Data/Database/GrDbConnectionInterceptor.cs create mode 100644 Data/Database/Repositories/AuthCodeRepository.cs create mode 100644 Data/Database/Repositories/GrRepository.cs create mode 100644 Data/Database/Repositories/IGrRepository.cs create mode 100644 Data/Database/Repositories/SubjectRepository.cs create mode 100644 Data/Database/Repositories/TokenMetadataRepository.cs create mode 100644 Data/Dto/AuthCodeDto.cs create mode 100644 Data/Dto/TokenDto.cs create mode 100644 Data/Entities/App/AppRelationEntity.cs create mode 100644 Data/Entities/App/AppSubjectRelationEntity.cs create mode 100644 Data/Entities/Base/EntityVisibility.cs create mode 100644 Data/Entities/Base/IEntity.cs create mode 100644 Data/Entities/Base/IMappingEntity.cs create mode 100644 Data/Entities/Base/IdData.cs create mode 100644 Data/Entities/Base/SubjectData.cs create mode 100644 Data/Entities/Base/TenantRelationData.cs create mode 100644 Data/Entities/Base/VisibilityData.cs create mode 100644 Data/Entities/ContentKeyAttribute.cs create mode 100644 Data/Entities/Security/AppUserRelationInternalAuthorityRelationEntity.cs create mode 100644 Data/Entities/Security/AuthCodeEntity.cs create mode 100644 Data/Entities/Security/AuthorityEntity.cs create mode 100644 Data/Entities/Security/AuthorityType.cs create mode 100644 Data/Entities/Security/TenantSubjectRelationInternalAuthorityRelationEntity.cs create mode 100644 Data/Entities/Security/TokenMetaDataEntity.cs create mode 100644 Data/Entities/Security/TokenType.cs create mode 100644 Data/Entities/Subject/SignIn/SignInEntity.cs create mode 100644 Data/Entities/Subject/SignIn/SignInMethod.cs create mode 100644 Data/Entities/Subject/SubjectEntity.cs create mode 100644 Data/Entities/Tenant/OwnerData.cs create mode 100644 Data/Entities/Tenant/TenantEntity.cs create mode 100644 Data/Entities/Tenant/TenantSubjectRelationEntity.cs create mode 100644 Data/Entities/Version/IVersionEntity.cs create mode 100644 Data/Entities/Version/VersionAction.cs create mode 100644 Data/Extensions/StringExtensions.cs create mode 100644 Data/Mapper/AuthCodeDtoMappingProfile.cs create mode 100644 Data/Migrations/20240903154112_sus.Designer.cs create mode 100644 Data/Migrations/20240903154112_sus.cs create mode 100644 Data/Migrations/20240914003536_addTokens.Designer.cs create mode 100644 Data/Migrations/20240914003536_addTokens.cs create mode 100644 Data/Migrations/20240914005530_affwaf.Designer.cs create mode 100644 Data/Migrations/20240914005530_affwaf.cs create mode 100644 Data/Migrations/20240914012943_fawfghh.Designer.cs create mode 100644 Data/Migrations/20240914012943_fawfghh.cs create mode 100644 Data/Migrations/20240914014850_gjjjjjj.Designer.cs create mode 100644 Data/Migrations/20240914014850_gjjjjjj.cs create mode 100644 Data/Migrations/20240914224344_jsoikgsoieg.Designer.cs create mode 100644 Data/Migrations/20240914224344_jsoikgsoieg.cs create mode 100644 Data/Migrations/20240919005908_afwawfawf.Designer.cs create mode 100644 Data/Migrations/20240919005908_afwawfawf.cs create mode 100644 Data/Migrations/20240919010339_ffffff.Designer.cs create mode 100644 Data/Migrations/20240919010339_ffffff.cs create mode 100644 Data/Migrations/20240919010748_jm├ñpromh.Designer.cs create mode 100644 Data/Migrations/20240919010748_jm├ñpromh.cs create mode 100644 Data/Migrations/20240919012025_fghdhhzttr.Designer.cs create mode 100644 Data/Migrations/20240919012025_fghdhhzttr.cs create mode 100644 Data/Migrations/20240921214234_kl├╢hmpdmpmgr.Designer.cs create mode 100644 Data/Migrations/20240921214234_kl├╢hmpdmpmgr.cs create mode 100644 Data/Migrations/ApplicationContextModelSnapshot.cs create mode 100644 Docker/docker-compose.yml create mode 100644 Scripts/add-migration.cmd create mode 100644 Scripts/reset-database.cmd create mode 100644 Scripts/update-database.cmd create mode 100644 Security/GrAuthorizeAttribute.cs create mode 100644 Security/Scheme/GandalfRebornJwtTokenAuthExtensions.cs create mode 100644 Security/Scheme/GandalfRebornJwtTokenAuthSchemeHandler.cs create mode 100644 Security/Scheme/GandalfRebornJwtTokenAuthSchemeOptions.cs create mode 100644 Security/Security.csproj create mode 100644 Service/Service.csproj create mode 100644 W542.GandalfReborn.sln diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..add57be --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ \ No newline at end of file diff --git a/.idea/.idea.W542.GandalfReborn/.idea/.gitignore b/.idea/.idea.W542.GandalfReborn/.idea/.gitignore new file mode 100644 index 0000000..7648847 --- /dev/null +++ b/.idea/.idea.W542.GandalfReborn/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/projectSettingsUpdater.xml +/contentModel.xml +/.idea.W542.GandalfReborn.iml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.W542.GandalfReborn/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.W542.GandalfReborn/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/.idea.W542.GandalfReborn/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.W542.GandalfReborn/.idea/dataSources.xml b/.idea/.idea.W542.GandalfReborn/.idea/dataSources.xml new file mode 100644 index 0000000..c500b12 --- /dev/null +++ b/.idea/.idea.W542.GandalfReborn/.idea/dataSources.xml @@ -0,0 +1,13 @@ + + + + + postgresql + true + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/gandalf_reborn?user=root&password=root + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/.idea.W542.GandalfReborn/.idea/indexLayout.xml b/.idea/.idea.W542.GandalfReborn/.idea/indexLayout.xml new file mode 100644 index 0000000..32440b5 --- /dev/null +++ b/.idea/.idea.W542.GandalfReborn/.idea/indexLayout.xml @@ -0,0 +1,11 @@ + + + + + Docker + Scripts + + + + + \ No newline at end of file diff --git a/.idea/.idea.W542.GandalfReborn/.idea/vcs.xml b/.idea/.idea.W542.GandalfReborn/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.W542.GandalfReborn/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Abstractions/Abstractions.csproj b/Abstractions/Abstractions.csproj new file mode 100644 index 0000000..3a63532 --- /dev/null +++ b/Abstractions/Abstractions.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Abstractions/Invoker.cs b/Abstractions/Invoker.cs new file mode 100644 index 0000000..3760f88 --- /dev/null +++ b/Abstractions/Invoker.cs @@ -0,0 +1,47 @@ +using System.Collections.Immutable; +using System.Security.Claims; +using System.Text.RegularExpressions; + +namespace Abstractions; + +public partial class Invoker +{ + public const string TenantAuthorityPrefix = "tenant-authority"; + public const string AppAuthorityPrefix = "app-authority"; + public const string AuthoritySeparator = ":"; + public const string SubType = "sub"; + + + public required long SubjectId { get; init; } + public required IReadOnlyDictionary> TenantAuthorityDictionary { get; init; } + public required IReadOnlyDictionary> AppAuthorityDictionary { get; init; } + public required bool IsAuthenticated { get; init; } + + [GeneratedRegex("(?" + TenantAuthorityPrefix + ")" + AuthoritySeparator + @"(?[a-zA-Z0-9]+)")] + private static partial Regex TenantAuthorityRegex(); + + [GeneratedRegex("(?" + AppAuthorityPrefix + ")" + AuthoritySeparator + @"(?[a-zA-Z0-9]+)")] + private static partial Regex AppAuthorityRegex(); + + public static implicit operator Invoker(ClaimsPrincipal claimsPrincipal) + { + var sub = claimsPrincipal.Claims.Where(x => x.Type == SubType).Select(x => (long?)long.Parse(x.Value)).SingleOrDefault(); + return new Invoker + { + SubjectId = sub.GetValueOrDefault(), + TenantAuthorityDictionary = claimsPrincipal.Claims + .Where(x => TenantAuthorityRegex().IsMatch(x.Type)) + .ToImmutableDictionary( + x => TenantAuthorityRegex().Match(x.Type).Groups["id"].Value, + x => claimsPrincipal.Claims.Where(y => y.Type == x.Type).Select(y => y.Value).ToHashSet() + ), + AppAuthorityDictionary = claimsPrincipal.Claims + .Where(x => AppAuthorityRegex().IsMatch(x.Type)) + .ToImmutableDictionary( + x => AppAuthorityRegex().Match(x.Type).Groups["id"].Value, + x => claimsPrincipal.Claims.Where(y => y.Type == x.Type).Select(y => y.Value).ToHashSet() + ), + IsAuthenticated = claimsPrincipal.Identity.IsAuthenticated + }; + } +} \ No newline at end of file diff --git a/Abstractions/InvokerContext.cs b/Abstractions/InvokerContext.cs new file mode 100644 index 0000000..12248b3 --- /dev/null +++ b/Abstractions/InvokerContext.cs @@ -0,0 +1,6 @@ +namespace Abstractions; + +public class InvokerContext +{ + public Abstractions.Invoker? Invoker { get; set; } +} \ No newline at end of file diff --git a/Api/Api.csproj b/Api/Api.csproj new file mode 100644 index 0000000..62200cf --- /dev/null +++ b/Api/Api.csproj @@ -0,0 +1,31 @@ + + + + net8.0 + enable + enable + W542.GandalfReborn + 12 + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/Api/Commands/AuthCodeRequestCommand.cs b/Api/Commands/AuthCodeRequestCommand.cs new file mode 100644 index 0000000..52b4e9a --- /dev/null +++ b/Api/Commands/AuthCodeRequestCommand.cs @@ -0,0 +1,18 @@ +using LanguageExt.Common; +using W542.GandalfReborn.Data.Dto; + +namespace W542.GandalfReborn.Commands; + +public class AuthCodeRequestCommand : IGrCommand> +{ + public required string UsernameOrEmail { get; set; } + public required string Password { get; set; } + public required string CodeChallenge { get; set; } + public required string Algorithm { get; set; } +}; + +public class GetTokensCommand : IGrCommand> +{ + public required string AuthCode { get; set; } + public required string ProofKey { get; set; } +}; \ No newline at end of file diff --git a/Api/Commands/CreateAuthCodeCommand.cs b/Api/Commands/CreateAuthCodeCommand.cs new file mode 100644 index 0000000..bf68754 --- /dev/null +++ b/Api/Commands/CreateAuthCodeCommand.cs @@ -0,0 +1,11 @@ +using LanguageExt.Common; +using W542.GandalfReborn.Data.Dto; + +namespace W542.GandalfReborn.Commands; + +public class CreateAuthCodeCommand : IGrCommand> +{ + public required long SubjectId { get; set; } + public required string CodeChallenge { get; set; } + public required string Algorithm { get; set; } +} \ No newline at end of file diff --git a/Api/Commands/CreateTokensCommand.cs b/Api/Commands/CreateTokensCommand.cs new file mode 100644 index 0000000..6d453c4 --- /dev/null +++ b/Api/Commands/CreateTokensCommand.cs @@ -0,0 +1,9 @@ +using LanguageExt.Common; +using W542.GandalfReborn.Data.Dto; + +namespace W542.GandalfReborn.Commands; + +public class CreateTokensCommand : IGrCommand> +{ + public required long SubjectId { get; set; } +} \ No newline at end of file diff --git a/Api/Commands/HashPasswordCommand.cs b/Api/Commands/HashPasswordCommand.cs new file mode 100644 index 0000000..fcb9de6 --- /dev/null +++ b/Api/Commands/HashPasswordCommand.cs @@ -0,0 +1,8 @@ +using LanguageExt.Common; + +namespace W542.GandalfReborn.Commands; + +public class HashPasswordCommand : IGrCommand> +{ + public required string RawPassword { get; set; } +} \ No newline at end of file diff --git a/Api/Commands/IGrCommand.cs b/Api/Commands/IGrCommand.cs new file mode 100644 index 0000000..ba4e4fd --- /dev/null +++ b/Api/Commands/IGrCommand.cs @@ -0,0 +1,5 @@ +using MediatR; + +namespace W542.GandalfReborn.Commands; + +public interface IGrCommand : IRequest; \ No newline at end of file diff --git a/Api/Commands/RegisterCommand.cs b/Api/Commands/RegisterCommand.cs new file mode 100644 index 0000000..6d2bee9 --- /dev/null +++ b/Api/Commands/RegisterCommand.cs @@ -0,0 +1,11 @@ +using LanguageExt.Common; +using W542.GandalfReborn.Data.Entities.Subject; + +namespace W542.GandalfReborn.Commands; + +public class RegisterCommand : IGrCommand> +{ + public required string Username { get; set; } + public required string Password { get; set; } + public required string Email { get; set; } +}; \ No newline at end of file diff --git a/Api/Controllers/AuthController.cs b/Api/Controllers/AuthController.cs new file mode 100644 index 0000000..cd2ad0a --- /dev/null +++ b/Api/Controllers/AuthController.cs @@ -0,0 +1,31 @@ +using MediatR; +using Microsoft.AspNetCore.Mvc; +using W542.GandalfReborn.Commands; + +namespace W542.GandalfReborn.Controllers; + +[ApiController] +[Route("api/[controller]")] +public class AuthController(IMediator mediator) : ControllerBase +{ + [HttpPost("[action]")] + public async Task Register([FromBody] RegisterCommand registerCommand) + { + var result = await mediator.Send(registerCommand); + return result.Match(Ok, e => BadRequest($"{e.Message}\n{e.InnerException?.Message}")); + } + + [HttpPost("[action]")] + public async Task Login([FromBody] AuthCodeRequestCommand authCodeRequestCommand) + { + var result = await mediator.Send(authCodeRequestCommand); + return result.Match(Ok, e => BadRequest($"{e.Message}\n{e.InnerException?.Message}")); + } + + [HttpPost("[action]")] + public async Task Token([FromBody] GetTokensCommand getTokensCommand) + { + var result = await mediator.Send(getTokensCommand); + return result.Match(Ok, e => BadRequest($"{e.Message}\n{e.InnerException?.Message}")); + } +} \ No newline at end of file diff --git a/Api/Extensions/ResultExtentions.cs b/Api/Extensions/ResultExtentions.cs new file mode 100644 index 0000000..6bff2bc --- /dev/null +++ b/Api/Extensions/ResultExtentions.cs @@ -0,0 +1,37 @@ +using LanguageExt.Common; + +namespace W542.GandalfReborn.Extensions; + +public static class ResultExtensions +{ + public static T GetValue(this Result result) + { + return result.Match( + x => x, + _ => default + )!; + } + + public static Result AsResult(this T result) + { + return new Result(result); + } + + public static Result AsErrorResult(this Result result) + { + return result.Match>( + _ => default, + e => new Result(e) + ); + } + + public static Result AsErrorResult(this Result result) + { + return result.AsErrorResult(); + } + + public static Result AsErrorResult(this string? errorMessage) + { + return new Result(new Exception(errorMessage)); + } +} \ No newline at end of file diff --git a/Api/Handlers/Commands/IGrCommandHandler.cs b/Api/Handlers/Commands/IGrCommandHandler.cs new file mode 100644 index 0000000..0aa0a56 --- /dev/null +++ b/Api/Handlers/Commands/IGrCommandHandler.cs @@ -0,0 +1,6 @@ +using MediatR; +using W542.GandalfReborn.Commands; + +namespace W542.GandalfReborn.Handlers.Commands; + +public interface IGrCommandHandler : IRequestHandler where TCommand : IGrCommand; \ No newline at end of file diff --git a/Api/Handlers/Commands/RegisterCommandHandler.cs b/Api/Handlers/Commands/RegisterCommandHandler.cs new file mode 100644 index 0000000..a0223e3 --- /dev/null +++ b/Api/Handlers/Commands/RegisterCommandHandler.cs @@ -0,0 +1,48 @@ +using LanguageExt.Common; +using MediatR; +using W542.GandalfReborn.Commands; +using W542.GandalfReborn.Data.Database.Repositories; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Subject.SignIn; +using W542.GandalfReborn.Data.Entities.Tenant; +using W542.GandalfReborn.Extensions; +using W542.GandalfReborn.Handlers.Security; + +namespace W542.GandalfReborn.Handlers.Commands; + +public class RegisterCommandHandler(ISubjectRepository subjectRepository, IMediator mediator) : IGrCommandHandler> +{ + public async Task> Handle(RegisterCommand command, CancellationToken cancellationToken) + { + var passwordHashResult = await mediator.Send(new HashPasswordCommand { RawPassword = command.Password }, cancellationToken); + + if (passwordHashResult.IsFaulted) + { + return passwordHashResult.AsErrorResult(); + } + + var passwordHash = passwordHashResult.GetValue(); + + var subject = new SubjectEntity + { + Visibility = EntityVisibility.Active, + Name = command.Username, + SignInMethods = + [ + new SignInEntity + { + Visibility = EntityVisibility.Active, + Method = SignInMethod.Simple, + IsLegacy = false, + PasswordHash = passwordHash, + Email = command.Email + } + ] + }; + + var upsertResult = await subjectRepository.Upsert(subject); + + return upsertResult; + } +} \ No newline at end of file diff --git a/Api/Handlers/Security/AuthCodeRequestCommandHandler.cs b/Api/Handlers/Security/AuthCodeRequestCommandHandler.cs new file mode 100644 index 0000000..1056782 --- /dev/null +++ b/Api/Handlers/Security/AuthCodeRequestCommandHandler.cs @@ -0,0 +1,69 @@ +using LanguageExt.Common; +using MediatR; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using W542.GandalfReborn.Commands; +using W542.GandalfReborn.Data.Database.Repositories; +using W542.GandalfReborn.Data.Dto; +using W542.GandalfReborn.Data.Entities.Subject.SignIn; +using W542.GandalfReborn.Extensions; +using W542.GandalfReborn.Handlers.Commands; + +namespace W542.GandalfReborn.Handlers.Security; + +public class AuthCodeRequestCommandHandler(IPasswordHasher passwordHasher, ISubjectRepository subjectRepository, IMediator mediator) : IGrCommandHandler> +{ + private static readonly object MicrosoftIsAMeme = new(); + + public async Task> Handle(AuthCodeRequestCommand command, CancellationToken cancellationToken) + { + var subjectResult = await subjectRepository.GetSingle(query => query + .Where(subject => subject.Name == command.UsernameOrEmail || subject.SignInMethods.Any(signIn => signIn.Method == SignInMethod.Simple && signIn.Email == command.UsernameOrEmail)) + .Include(x => x.SignInMethods) + ); + + if (subjectResult.IsFaulted) + { + return $"User {command.UsernameOrEmail} does not exist.".AsErrorResult(); + } + + var subject = subjectResult.GetValue(); + + var simpleSignIn = subject.SignInMethods.SingleOrDefault(x => x.Method == SignInMethod.Simple); + + if (simpleSignIn?.PasswordHash is null) + { + return "User does not support simple password.".AsErrorResult(); + } + + var verification = passwordHasher.VerifyHashedPassword(MicrosoftIsAMeme, simpleSignIn.PasswordHash, command.Password); + + switch (verification) + { + case PasswordVerificationResult.Failed: + return "Wrong Password.".AsErrorResult(); + + case PasswordVerificationResult.Success: + return await mediator.Send(new CreateAuthCodeCommand { SubjectId = subject.Id!.Value, CodeChallenge = command.CodeChallenge, Algorithm = command.Algorithm }, cancellationToken); + + case PasswordVerificationResult.SuccessRehashNeeded: + var newHashResult = await mediator.Send(new HashPasswordCommand { RawPassword = command.Password }, cancellationToken); + + if (newHashResult.IsFaulted) + { + return newHashResult.AsErrorResult(); + } + + var newHash = newHashResult.GetValue(); + + simpleSignIn.PasswordHash = newHash; + + await subjectRepository.SaveChanges(); + + return await mediator.Send(new CreateAuthCodeCommand { SubjectId = subject.Id!.Value, CodeChallenge = command.CodeChallenge, Algorithm = command.Algorithm }, cancellationToken); + + default: + return $"Password verification type not supported: {verification}".AsErrorResult(); + } + } +} \ No newline at end of file diff --git a/Api/Handlers/Security/CreateAuthCodeCommandHandler.cs b/Api/Handlers/Security/CreateAuthCodeCommandHandler.cs new file mode 100644 index 0000000..1d161f0 --- /dev/null +++ b/Api/Handlers/Security/CreateAuthCodeCommandHandler.cs @@ -0,0 +1,38 @@ +using AutoMapper; +using LanguageExt.Common; +using Microsoft.AspNetCore.Identity; +using W542.GandalfReborn.Commands; +using W542.GandalfReborn.Data.Database.Repositories; +using W542.GandalfReborn.Data.Dto; +using W542.GandalfReborn.Data.Entities.Security; +using W542.GandalfReborn.Handlers.Commands; + +namespace W542.GandalfReborn.Handlers.Security; + +public class CreateAuthCodeCommandHandler(IPasswordHasher passwordHasher, TimeProvider timeProvider, IAuthCodeRepository authCodeRepository, IMapper mapper) : IGrCommandHandler> +{ + private static readonly object MicrosoftIsAMeme = new(); + + public async Task> Handle(CreateAuthCodeCommand command, CancellationToken cancellationToken) + { + var code = passwordHasher.HashPassword(MicrosoftIsAMeme, command.SubjectId.ToString()); + var expiresAt = timeProvider.GetUtcNow().AddMinutes(5); + + var authCodeEntity = new AuthCodeEntity + { + SubjectId = command.SubjectId, + Expiration = expiresAt, + IsRevoked = false, + Code = code, + Challenge = command.CodeChallenge, + Algorithm = command.Algorithm, + }; + + var insertedAuthCodeEntity = await authCodeRepository.Upsert(authCodeEntity); + + return insertedAuthCodeEntity.Match( + success => mapper.Map(success), + fail => new Result(fail) + ); + } +} \ No newline at end of file diff --git a/Api/Handlers/Security/CreateTokensCommandHandler.cs b/Api/Handlers/Security/CreateTokensCommandHandler.cs new file mode 100644 index 0000000..0b67b83 --- /dev/null +++ b/Api/Handlers/Security/CreateTokensCommandHandler.cs @@ -0,0 +1,79 @@ +using HashidsNet; +using JWT.Algorithms; +using JWT.Builder; +using JWT.Serializers; +using LanguageExt.Common; +using Security.Scheme; +using W542.GandalfReborn.Commands; +using W542.GandalfReborn.Data.Database.Repositories; +using W542.GandalfReborn.Data.Dto; +using W542.GandalfReborn.Data.Entities.Security; +using W542.GandalfReborn.Extensions; +using W542.GandalfReborn.Handlers.Commands; + +namespace W542.GandalfReborn.Handlers.Security; + +public class CreateTokensCommandHandler(TimeProvider timeProvider, IConfiguration configuration, IHashids hashids, ITokenMetadataRepository tokenMetadataRepository) : IGrCommandHandler> +{ + public async Task> Handle(CreateTokensCommand command, CancellationToken cancellationToken) + { + var iat = timeProvider.GetUtcNow(); + var accessExp = iat.AddMinutes(5); + var refreshExp = iat.AddDays(7); + + var builder = JwtBuilder.Create() + .WithAlgorithm(new HMACSHA512Algorithm()) + .WithSecret(configuration.GetValue("JwtSecret")) + .WithJsonSerializer(new JsonNetSerializer()); + + var accessTokenMetadata = new TokenMetadataEntity + { + Expiration = accessExp, + IsRevoked = false, + TokenType = TokenType.User, + UsedBy = command.SubjectId + }; + + var refreshTokenMetadata = new TokenMetadataEntity + { + Expiration = refreshExp, + IsRevoked = false, + TokenType = TokenType.User, + UsedBy = command.SubjectId + }; + + var entities = await tokenMetadataRepository.Upsert([accessTokenMetadata, refreshTokenMetadata]); + + if (entities.IsFaulted) + return entities.AsErrorResult>(); + + var baseUrl = configuration.GetValue("BaseUrl") ?? "https://localhost:7269"; + + var accessToken = builder.Encode(new GandalfRebornJwtBody + { + Id = hashids.EncodeLong(accessTokenMetadata.Id!.Value), + Sub = hashids.EncodeLong(command.SubjectId), + Iat = iat, + Exp = accessExp, + Iss = baseUrl, + Aud = baseUrl + + }); + + var refreshToken = builder.Encode(new GandalfRebornJwtBody + { + Id = hashids.EncodeLong(refreshTokenMetadata.Id!.Value), + Sub = hashids.EncodeLong(command.SubjectId), + Iat = iat, + Exp = refreshExp, + Iss = baseUrl, + Aud = baseUrl + }); + + return new Result(new TokenDto + { + AccessToken = accessToken, + RefreshToken = refreshToken + }); + } +} \ No newline at end of file diff --git a/Api/Handlers/Security/GetTokensCommandHandler.cs b/Api/Handlers/Security/GetTokensCommandHandler.cs new file mode 100644 index 0000000..da4491e --- /dev/null +++ b/Api/Handlers/Security/GetTokensCommandHandler.cs @@ -0,0 +1,57 @@ +using System.Security.Cryptography; +using System.Text; +using LanguageExt.Common; +using MediatR; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using W542.GandalfReborn.Commands; +using W542.GandalfReborn.Data.Database.Repositories; +using W542.GandalfReborn.Data.Dto; +using W542.GandalfReborn.Extensions; +using W542.GandalfReborn.Handlers.Commands; + +namespace W542.GandalfReborn.Handlers.Security; + +public class GetTokensCommandHandler(IAuthCodeRepository authCodeRepository, TimeProvider timeProvider, IMediator mediator) : IGrCommandHandler> +{ + public async Task> Handle(GetTokensCommand command, CancellationToken cancellationToken) + { + var authCode = await authCodeRepository + .Query(q => q.Where(x => x.Code == command.AuthCode)) + .SingleOrDefaultAsync(cancellationToken); + + if (authCode is null) + { + return "Auth code could not be found.".AsErrorResult(); + } + + if (authCode.Expiration <= timeProvider.GetUtcNow()) + { + await authCodeRepository + .Query(q => q.Where(x => x.Id == authCode.Id)) + .ExecuteDeleteAsync(cancellationToken); + + return "Auth code is expired.".AsErrorResult(); + } + + switch (authCode.Algorithm) + { + case "S256": + var proofKeyBytes = Encoding.UTF8.GetBytes(command.ProofKey); + var sha256Bytes = SHA256.HashData(proofKeyBytes); + var hexProofKey = BitConverter.ToString(sha256Bytes).Replace("-", string.Empty).ToLower(); + if (authCode.Challenge != hexProofKey) + return "Code challenge failed.".AsErrorResult(); + break; + + default: + return $"Algorithm '{authCode.Algorithm}' not supported".AsErrorResult(); + } + + await authCodeRepository + .Query(q => q.Where(x => x.Id == authCode.Id)) + .ExecuteDeleteAsync(cancellationToken); + + return await mediator.Send(new CreateTokensCommand {SubjectId = authCode.SubjectId}, cancellationToken); + } +} \ No newline at end of file diff --git a/Api/Handlers/Security/PasswordHashingHandler.cs b/Api/Handlers/Security/PasswordHashingHandler.cs new file mode 100644 index 0000000..760530f --- /dev/null +++ b/Api/Handlers/Security/PasswordHashingHandler.cs @@ -0,0 +1,26 @@ +using LanguageExt.Common; +using Microsoft.AspNetCore.Identity; +using W542.GandalfReborn.Commands; +using W542.GandalfReborn.Extensions; +using W542.GandalfReborn.Handlers.Commands; + +namespace W542.GandalfReborn.Handlers.Security; + +public class PasswordHashingHandler(IPasswordHasher passwordHasher) : IGrCommandHandler> +{ + private static readonly object MicrosoftIsAMeme = new(); + + public Task> Handle(HashPasswordCommand command, CancellationToken cancellationToken) + { + try + { + var hash = passwordHasher.HashPassword(MicrosoftIsAMeme, command.RawPassword); + return Task.FromResult(hash.AsResult()); + } + catch (Exception) + { + return Task.FromResult("Something went wrong while hashing password.".AsErrorResult()); + } + + } +} \ No newline at end of file diff --git a/Api/Program.cs b/Api/Program.cs new file mode 100644 index 0000000..4851be8 --- /dev/null +++ b/Api/Program.cs @@ -0,0 +1,76 @@ +using System.Reflection; +using System.Text.Json.Serialization; +using Abstractions; +using HashidsNet; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using Security; +using Security.Scheme; +using W542.GandalfReborn.Data.Database; +using W542.GandalfReborn.Data.Database.Repositories; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + +builder.Services.AddSingleton(TimeProvider.System); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); +builder.Services.AddDbContext(cfg => cfg + .UseNpgsql( + builder.Configuration.GetConnectionString("DefaultConnection"), + x => x.MigrationsAssembly("Data") + ) +); + +builder.Services.AddAutoMapper(typeof(ApplicationContext).Assembly); + +builder.Services.Configure(opt => +{ + opt.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV3; + opt.IterationCount = 210_000; +}); +builder.Services.AddSingleton>(new PasswordHasher()); +builder.Services.AddScoped(); + +builder.Services.AddSingleton(new Hashids(builder.Configuration.GetValue("HashIdSalt") ?? "superSalt", 12)); +builder.Services.AddGandalfRebornJwtTokenAuth(options => +{ + options.JwtSecret = builder.Configuration.GetValue("JwtSecret") ?? "superSecret"; + options.BaseUrl = builder.Configuration.GetValue("BaseUrl") ?? ""; +}); +builder.Services.AddSingleton(); +builder.Services.AddRouting(options => options.LowercaseUrls = true); +builder.Services.AddControllers().AddJsonOptions(options => +{ + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); +}); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddMediatR(config => +{ + config.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); +}); +var app = builder.Build(); + +var scope = app.Services.CreateScope(); +var applicationContext = scope.ServiceProvider.GetRequiredService(); +applicationContext.Database.EnsureCreated(); +applicationContext.AddVersionTriggers(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); +app.MapControllers(); + +app.Run(); \ No newline at end of file diff --git a/Api/Properties/launchSettings.json b/Api/Properties/launchSettings.json new file mode 100644 index 0000000..0608cc5 --- /dev/null +++ b/Api/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:48302", + "sslPort": 44338 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5035", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7269;http://localhost:5035", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": false, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Api/TestController.cs b/Api/TestController.cs new file mode 100644 index 0000000..f6a6d40 --- /dev/null +++ b/Api/TestController.cs @@ -0,0 +1,105 @@ +using Abstractions; +using HashidsNet; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Security; +using W542.GandalfReborn.Data.Database; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Security; +using W542.GandalfReborn.Data.Entities.Tenant; + +namespace W542.GandalfReborn; + +[ApiController] +[Route("api/[controller]")] +[Authorize] +public class TestController(IHashids hashids, ApplicationContext context, InvokerContext invokerContext) : ControllerBase +{ + [HttpGet("[action]")] + public IActionResult Get() + { + // return all the user claims in all identities + return Ok((Invoker)User); + } + + [HttpPost("tenant")] + public async Task AddTenant([FromBody] CreateTenantCommand command) + { + var invoker = invokerContext.Invoker!; + + var authorities = await context.AuthorityEntities.Where(x => x.Type == AuthorityType.Tenant).ToListAsync(); + + var tenantSubjectRelationEntity = new TenantSubjectRelationEntity + { + Tenant = new TenantEntity + { + Visibility = EntityVisibility.Active, + OwnerId = invoker.SubjectId, + Name = command.Name + }, + SubjectId = invoker.SubjectId, + InternalAuthorities = authorities.ToHashSet() + }; + + await context.AddAsync(tenantSubjectRelationEntity); + await context.SaveChangesAsync(); + + return Ok(tenantSubjectRelationEntity.Tenant); + } + + [HttpPut("tenant/{id:long}")] + public async Task UpdateTenant(long id, [FromBody] UpdateTenantCommand command) + { + var invoker = (Invoker)User; + + var tenant = context.Tenants.Single(x => x.Id == id); + + tenant.Name = command.Name; + + await context.SaveChangesAsync(); + + return Ok(tenant); + } + + + [HttpGet("tenant")] + public async Task GetTenants() + { + var invoker = (Invoker)User; + + var tenants = await context.TenantSubjectRelations.Where(x => x.SubjectId == invoker.SubjectId).Select(x => hashids.EncodeLong(x.TenantId)).ToListAsync(); + + return Ok(tenants); + } + + [GrAuthorize(Type = AuthorityType.Tenant, Authorities = [TenantAuthority.Read], ParameterName = "id")] + [HttpGet("tenant/{id}")] + public async Task GetTenant(string id) + { + if(!hashids.TryDecodeSingleLong(id, out var decodedId)) return BadRequest("One does not simply use a invalid id."); + + var tenant = await context.Tenants.Where(x => x.Id == decodedId).SingleOrDefaultAsync(); + + if(tenant is null) return BadRequest("One does not simply request unknown tenant."); + + return Ok(tenant); + } + + [AllowAnonymous] + [HttpGet("hashid/encode/{id:long}")] + public IActionResult GetHashId(long id) + { + return Ok(hashids.EncodeLong(id)); + } + + [AllowAnonymous] + [HttpGet("hashid/decode/{id}")] + public IActionResult GetHashId(string id) + { + return Ok(hashids.DecodeSingleLong(id)); + } +} + +public record UpdateTenantCommand(string Name); +public record CreateTenantCommand(string Name); \ No newline at end of file diff --git a/Api/appsettings.Development.json b/Api/appsettings.Development.json new file mode 100644 index 0000000..f1b3795 --- /dev/null +++ b/Api/appsettings.Development.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "DefaultConnection": "Server=localhost;Database=gandalf_reborn;Port=5432;User Id=root;Password=root;Include Error Detail=True" + }, + "HashIdSalt": "RD7MTWZsTm2DVF9WAksbpzp`Daccgk&4w~Qk^v99W~LtpXefUt2b5~~o52#7q^MzRC`3U^@%SLAp%QF$xr@fZ$TgA@vrD5qkwovv%9Rb`MEUEr4TSNLuXq7P9yQTH~dRvk`x~ueEPvup^c7w`wfo7EoQWJa99dSe%wLy`R7iyz~kZ$JR$QhqwM4pcHFtxLtSf^QdtLhssZipKi9T#J%EP#9jQR&NC$q5Pt4J7oyYq~WyfbAYZxMMc~s4Qoonnyyh", + "JwtSecret": "sPKw4qrxSDrVAPMkpfXRmrmY#%f`@im&nrzhTYJSbg7jDEePaoobzvTx$q@Dt3`^xEVquT&XW%evc`7rR`^j%2MnHrHrxAteC5CADguRDQHN5HfS%^2PJ7VWJwn~YV2c~aSe`T@wPPLwnwbpSk~E%wxMfUbDDm#XZh7Z@9t24uiT9nxQpt^ZKcSc#CEeW4^#hc^vaLkeYT73RcC#&vSZMdr5e$Z~i&f$73%z@^yyAoFutLPmtgjosDW3mPb4z~h^", + "BaseUrl": "https://localhost:7269" +} diff --git a/Api/appsettings.json b/Api/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/Api/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Core/Core.csproj b/Core/Core.csproj new file mode 100644 index 0000000..253a407 --- /dev/null +++ b/Core/Core.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + enable + enable + W542.GandalfReborn.Core + 12 + + + + + + + + + + + + diff --git a/Data/Data.csproj b/Data/Data.csproj new file mode 100644 index 0000000..56d3967 --- /dev/null +++ b/Data/Data.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + enable + enable + W542.GandalfReborn.Data + 12 + + + + + + + + + + + + CoreContext.cs + + + + + + + + diff --git a/Data/Database/ApplicationContext.cs b/Data/Database/ApplicationContext.cs new file mode 100644 index 0000000..875e840 --- /dev/null +++ b/Data/Database/ApplicationContext.cs @@ -0,0 +1,206 @@ +using Abstractions; +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Security; +using W542.GandalfReborn.Data.Entities.Tenant; +using W542.GandalfReborn.Data.Entities.Version; +using W542.GandalfReborn.Data.Extensions; + +namespace W542.GandalfReborn.Data.Database; + +public sealed class ApplicationContext(DbContextOptions options, InvokerContext invokerContext) : CoreContext(options) +{ + private static readonly Dictionary EntityToVersionEntityMap = new(); + private const string Schema = "gr"; + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.AddInterceptors(new GrDbConnectionInterceptor(invokerContext)); + } + + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + + ConfigureId(builder); + AddEnumToStringConversion(builder); + AddVersionRelations(builder); + SetTableNames(builder); + } + + private static void ConfigureId(ModelBuilder builder) + { + var longKeyEntities = builder.Model + .GetEntityTypes() + .Where(x => !x.ClrType.GetInterfaces().Any(y => y.IsGenericType && y.GetGenericTypeDefinition().IsAssignableTo(typeof(IVersionEntity<>)))) + .Where(x => !x.ClrType.GetInterfaces().Any(y => y.IsAssignableTo(typeof(IMappingEntity)))) + .Where(x => x.GetProperties().Any(y => y.Name == nameof(IdData.Id) && y.ClrType == typeof(long))) + .ToList(); + + foreach (var entity in longKeyEntities) + // var idSequenceName = $"{entity.ClrType.Name.Replace("Entity", string.Empty)}_{nameof(IdData.Id)}_{IdSequenceSuffix}"; + // builder.HasSequence(idSequenceName).IncrementsBy(100); + builder.Entity(entity.ClrType) + .Property(nameof(IdData.Id)) + // .UseIdentityAlwaysColumn(); + .ValueGeneratedOnAdd(); + // .UseHiLo(idSequenceName) + // .HasColumnType("bigserial"); + } + + private static void AddVersionRelations(ModelBuilder builder) + { + // var coreTypes = typeof(CoreContext).Assembly + // .GetTypes() + // .Where(x => x is { IsAbstract: false, IsInterface: false } && x.GetInterfaces().Any(y => y.IsGenericType && y.GetGenericTypeDefinition() == typeof(IVersionEntity<>))); + + var dataTypes = typeof(ApplicationContext).Assembly + .GetTypes() + .Where(x => x is { IsAbstract: false, IsInterface: false } && x.GetInterfaces().Any(y => y.IsGenericType && y.GetGenericTypeDefinition() == typeof(IVersionEntity<>))); + + // var allVersionTypes = coreTypes.Concat(dataTypes).ToList(); + + foreach (var type in dataTypes) + { + var entityBuilder = builder.Entity(type); + + var referenceType = type.GetProperties() + .Where(x => x.Name == nameof(IVersionEntity.Reference)) + .Select(x => x.PropertyType) + .Single(); + + EntityToVersionEntityMap.TryAdd(referenceType, type); + + var referencePrimaryKeys = builder.Model + .GetEntityTypes() + .Where(x => x.ClrType == referenceType) + .Select(x => x.FindPrimaryKey()) + .Single(x => x is not null)! + .Properties + .Select(x => x.Name) + .ToArray(); + + entityBuilder + .HasKey([..referencePrimaryKeys, nameof(IVersionEntity.At)]); + + entityBuilder + .HasOne(nameof(IVersionEntity.Reference)) + .WithMany() + .HasForeignKey(referencePrimaryKeys) + .IsRequired(); + + entityBuilder + .HasOne(nameof(IVersionEntity.Suspect)) + .WithMany() + .HasForeignKey(nameof(IVersionEntity.SuspectId)) + .IsRequired(); + } + + var versionTypes = builder.Model + .GetEntityTypes() + .Where(x => x.ClrType is { IsAbstract: false, IsInterface: false } && x.ClrType.GetInterfaces().Any(y => y.IsGenericType && y.GetGenericTypeDefinition() == typeof(IVersionEntity<>))) + .ToList(); + + versionTypes.ForEach(type => + { + var allowedNavigationNames = new List + { + nameof(IVersionEntity.Reference), + nameof(IVersionEntity.Suspect) + }; + + var navigations = type + .GetNavigations() + .Where(x => !allowedNavigationNames.Contains(x.Name)) + .ToList(); + + var entityBuilder = builder.Entity(type.ClrType); + + navigations.ForEach(x => entityBuilder.Ignore(x.Name)); + }); + } + + public void AddVersionTriggers() + { + foreach (var (entityType, versionType) in EntityToVersionEntityMap) + { + var dataType = entityType.BaseType; + + if (dataType == null) + throw new Exception($"Could not find base type for {entityType}"); + + var dataTypeColumns = dataType.GetProperties().Select(x => x.Name).ToList(); + var versionTypeColumns = new Dictionary() + { + [nameof(IVersionEntity.At)] = "current_timestamp", + [nameof(IVersionEntity.SuspectId)] = $"current_setting('{GrDbConnectionInterceptor.CurrentSuspectKey}', 't')::bigint", + [nameof(IVersionEntity.Action)] = $"(CASE WHEN (tg_op = 'INSERT') THEN '{VersionAction.Created.ToString()}' ELSE '{VersionAction.Modified.ToString()}' END)" + }; + + var rowColumns = string.Join(", ", dataTypeColumns.Concat(versionTypeColumns.Keys).Select(x => $"\"{x}\"")); + var rowValues = string.Join(", ", dataTypeColumns.Select(x => $"NEW.\"{x}\"").Concat(versionTypeColumns.Values)); + + // Trust me, never change those names. + var triggerName = $"{GetTableName(entityType).ToLower()}_t"; + var functionName = $"p_{triggerName}"; + + var sql = $""" + CREATE OR REPLACE FUNCTION {Schema}.{functionName}() + RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + insert into {Schema}."{GetTableName(versionType)}" ({rowColumns}) + values ({rowValues}); + RETURN NEW; + END; + $$; + + CREATE OR REPLACE TRIGGER {triggerName} AFTER INSERT Or UPDATE ON {Schema}."{GetTableName(entityType)}" + FOR EACH ROW + EXECUTE FUNCTION {Schema}.{functionName}(); + """; + +#pragma warning disable EF1002 + Database.ExecuteSqlRaw(sql); +#pragma warning restore EF1002 + } + } + + private static void AddEnumToStringConversion(ModelBuilder builder) + { + var entityTypes = builder.Model.GetEntityTypes().ToList(); + + foreach (var type in entityTypes) + { + var entityBuilder = builder.Entity(type.ClrType); + + var propertyInfos = type.ClrType.GetProperties(); + foreach (var property in propertyInfos) + if (property.PropertyType.IsEnum) + entityBuilder + .Property(property.Name) + .HasConversion(); + } + } + + private static void SetTableNames(ModelBuilder builder) + { + var entityTypes = builder.Model + .GetEntityTypes(); + + foreach (var type in entityTypes) + { + var entityBuilder = builder.Entity(type.ClrType); + var tableName = GetTableName(type.ClrType); + entityBuilder.ToTable(tableName, Schema); + } + } + + private static string GetTableName(Type entityType) + { + return $"{entityType.Name.Replace("Entity", string.Empty)}"; + } +} \ No newline at end of file diff --git a/Data/Database/CoreContext.cs b/Data/Database/CoreContext.cs new file mode 100644 index 0000000..1015ef3 --- /dev/null +++ b/Data/Database/CoreContext.cs @@ -0,0 +1,208 @@ +using Microsoft.EntityFrameworkCore; +using W542.GandalfReborn.Data.Entities.App; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Security; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Subject.SignIn; +using W542.GandalfReborn.Data.Entities.Tenant; + +namespace W542.GandalfReborn.Data.Database; + +public abstract class CoreContext(DbContextOptions options) : DbContext(options) where T : DbContext +{ + public DbSet Tenants { get; set; } + public DbSet Subjects { get; set; } + public DbSet Apps { get; set; } + public DbSet TenantSubjectRelations { get; set; } + public DbSet AppSubjectRelations { get; set; } + public DbSet AuthorityEntities { get; set; } + public DbSet TokenMetadata { get; set; } + public DbSet AuthCodes { get; set; } + + public DbSet AppsVersions { get; set; } + public DbSet TenantVersions { get; set; } + public DbSet AppSubjectRelationVersions { get; set; } + public DbSet TenantSubjectRelationVersions { get; set; } + public DbSet AppSubjectRelationInternalAuthorityRelationVersions { get; set; } + public DbSet TenantSubjectRelationInternalAuthorityRelationVersions { get; set; } + + protected override void OnModelCreating(ModelBuilder builder) + { + #region Tenant + + var tenantBuilder = builder.Entity(); + + tenantBuilder + .HasMany(x => x.Subjects) + .WithMany(x => x.Tenants) + .UsingEntity( + r => r + .HasOne(x => x.Subject) + .WithMany() + .HasForeignKey(x => x.SubjectId), + l => l + .HasOne(x => x.Tenant) + .WithMany() + .HasForeignKey(x => x.TenantId), + j => j + .HasKey(x => new { x.SubjectId, x.TenantId }) + ); + + tenantBuilder + .HasOne(x => x.Owner) + .WithMany() + .HasForeignKey(x => x.OwnerId) + .IsRequired(); + + #endregion + + #region TenantSubjectRelation + + var tenantSubjectRelationBuilder = builder.Entity(); + + tenantSubjectRelationBuilder + .HasMany(x => x.InternalAuthorities) + .WithMany(x => x.TenantSubjectRelations) + .UsingEntity( + r => r + .HasOne(x => x.InternalAuthority) + .WithMany() + .HasForeignKey(x => x.InternalAuthorityId), + l => l + .HasOne(x => x.TenantSubjectRelation) + .WithMany() + .HasForeignKey(x => new { x.SubjectId, x.TenantId }), + j => j + .HasKey(x => new { x.SubjectId, x.TenantId, x.InternalAuthorityId }) + ) + .HasKey(x => new { x.SubjectId, x.TenantId }); + + #endregion + + #region Subject + + var subjectBuilder = builder.Entity(); + + subjectBuilder + .HasMany(x => x.SignInMethods) + .WithOne(x => x.Subject) + .HasForeignKey(x => x.SubjectId) + .IsRequired(); + + subjectBuilder + .HasIndex(x => x.Name) + .IsUnique(); + + subjectBuilder + .HasData(new SubjectEntity + { + Id = 1, + Visibility = EntityVisibility.Active, + Name = "chris" + }); + + #endregion + + #region SighnIns + + var signInBuilder = builder.Entity(); + + signInBuilder + .HasIndex(x => x.Email) + .IsUnique(); + + #endregion + + #region App + + var appBuilder = builder.Entity(); + + appBuilder + .HasMany(x => x.Subjects) + .WithMany(x => x.Apps) + .UsingEntity( + r => r + .HasOne(x => x.Subject) + .WithMany() + .HasForeignKey(x => x.SubjectId), + l => l + .HasOne(x => x.App) + .WithMany() + .HasForeignKey(x => x.AppId), + j => j + .HasKey(x => new { x.SubjectId, x.AppId }) + ); + + appBuilder + .HasOne(x => x.Tenant) + .WithMany(x => x.Apps) + .HasForeignKey(x => x.TenantId); + + #endregion + + #region AppSubjectRelation + + var appSubjectRelationBuilder = builder.Entity(); + + appSubjectRelationBuilder + .HasMany(x => x.InternalAuthorities) + .WithMany(x => x.AppSubjectRelations) + .UsingEntity( + r => r + .HasOne(x => x.InternalAuthority) + .WithMany() + .HasForeignKey(x => x.InternalAuthorityId), + l => l + .HasOne(x => x.AppSubjectRelation) + .WithMany() + .HasForeignKey(x => new { x.SubjectId, x.AppId }), + j => j + .HasKey(x => new { x.SubjectId, x.AppId, x.InternalAuthorityId }) + ) + .HasKey(x => new { x.SubjectId, x.AppId }); + + #endregion + + #region Authority + + var authorityBuilder = builder.Entity(); + + authorityBuilder + .HasData( + new AuthorityEntity + { + Id = 1, + Type = AuthorityType.Tenant, + Name = "Tenant_Read", + Description = "Allows users to read tenants" + }, new AuthorityEntity + { + Id = 2, + Type = AuthorityType.App, + Name = "App_Read", + Description = "Allows users to read apps" + } + ); + + authorityBuilder + .HasKey(x => x.Id); + + authorityBuilder + .HasIndex(x => x.Name) + .IsUnique(); + + #endregion + + #region Tokens + + builder.Entity(); + + #endregion + + #region AuthCodes + + builder.Entity(); + + #endregion + } +} \ No newline at end of file diff --git a/Data/Database/GrDbConnectionInterceptor.cs b/Data/Database/GrDbConnectionInterceptor.cs new file mode 100644 index 0000000..771af97 --- /dev/null +++ b/Data/Database/GrDbConnectionInterceptor.cs @@ -0,0 +1,23 @@ +using System.Data; +using System.Data.Common; +using Abstractions; +using Microsoft.EntityFrameworkCore.Diagnostics; + +namespace W542.GandalfReborn.Data.Database; + +public class GrDbConnectionInterceptor(InvokerContext invokerContext) : IDbConnectionInterceptor +{ + public const string CurrentSuspectKey = "gr.current.suspect"; + public async Task ConnectionOpenedAsync(DbConnection connection, ConnectionEndEventData eventData, CancellationToken cancellationToken = new()) + { + if (invokerContext.Invoker is null) + return; + + var command = connection.CreateCommand(); + command.CommandType = CommandType.Text; + command.CommandText = $""" + SET SESSION "{CurrentSuspectKey}" = {invokerContext.Invoker.SubjectId}; + """; + await command.ExecuteNonQueryAsync(cancellationToken); + } +} \ No newline at end of file diff --git a/Data/Database/Repositories/AuthCodeRepository.cs b/Data/Database/Repositories/AuthCodeRepository.cs new file mode 100644 index 0000000..1319d03 --- /dev/null +++ b/Data/Database/Repositories/AuthCodeRepository.cs @@ -0,0 +1,14 @@ +using System.Linq.Expressions; +using LanguageExt.Common; +using Microsoft.EntityFrameworkCore; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Security; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Tenant; +using W542.GandalfReborn.Data.Entities.Version; + +namespace W542.GandalfReborn.Data.Database.Repositories; + +public class AuthCodeRepository(ApplicationContext context) : GrRepository(context), IAuthCodeRepository; + +public interface IAuthCodeRepository : IGrRepository; \ No newline at end of file diff --git a/Data/Database/Repositories/GrRepository.cs b/Data/Database/Repositories/GrRepository.cs new file mode 100644 index 0000000..b280a2a --- /dev/null +++ b/Data/Database/Repositories/GrRepository.cs @@ -0,0 +1,112 @@ +using LanguageExt.Common; +using Microsoft.EntityFrameworkCore; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Tenant; + +namespace W542.GandalfReborn.Data.Database.Repositories; + +public abstract class GrRepository(ApplicationContext context) : IGrRepository where TEntity : class, IEntity +{ + public async Task> SaveChanges() + { + try + { + await context.SaveChangesAsync(); + return true; + } + catch (Exception e) + { + return new Result(e); + } + } + + public async Task> GetSingle(Func, IQueryable>? query, bool tracked = true) + { + IQueryable set = context.Set(); + + if (query is not null) + { + set = query.Invoke(set); + } + + if (!tracked) + { + set = set.AsNoTracking(); + } + + var result = await set.SingleOrDefaultAsync(); + + return result ?? new Result(new Exception("Not found.")); + } + + public async Task>> GetMany(Func, IQueryable>? query, bool tracked = true) + { + IQueryable set = context.Set(); + + if (query is not null) + { + set = query.Invoke(set); + } + + if (!tracked) + { + set = set.AsNoTracking(); + } + + var result = await set.ToListAsync(); + + return result; + } + + public async Task> Upsert(TEntity entity) + { + var result = await Upsert([entity]); + return result.Match( + success => + { + if (success.Count != 1) + { + return new Result(new Exception("Something very sus happened during upsert. Input count != output count?")); + } + + return success.Single(); + }, + fail => new Result(fail) + ); + } + + public async Task>> Upsert(ICollection entities) + { + var newEntities = entities.Where(x => x.Id is null).ToList(); + var updatedEntities = entities.Where(x => x.Id is not null).ToList(); + + try + { + context.AddRange(newEntities); + context.UpdateRange(updatedEntities); + await context.SaveChangesAsync(); + } + catch (Exception e) + { + return new Result>(e); + } + + return new Result>(entities); + } + + public IQueryable Query(Func, IQueryable> query) + { + return Query(query); + } + + private IQueryable Query(Func, IQueryable> query) where TIn : class, IEntity + { + IQueryable set = context.Set(); + return query.Invoke(set); + } + + public IQueryable Query(Func, IQueryable> query) + { + return Query(query); + } +} \ No newline at end of file diff --git a/Data/Database/Repositories/IGrRepository.cs b/Data/Database/Repositories/IGrRepository.cs new file mode 100644 index 0000000..500f037 --- /dev/null +++ b/Data/Database/Repositories/IGrRepository.cs @@ -0,0 +1,18 @@ +using LanguageExt.Common; +using W542.GandalfReborn.Data.Entities.Base; + +namespace W542.GandalfReborn.Data.Database.Repositories; + +public interface IGrRepository where TEntity : class, IEntity +{ + Task> SaveChanges(); + + Task> GetSingle(Func, IQueryable>? query, bool tracked = true); + Task>> GetMany(Func, IQueryable>? query, bool tracked = true); + + Task> Upsert(TEntity entity); + Task>> Upsert(ICollection entities); + + IQueryable Query(Func, IQueryable> query); + IQueryable Query(Func, IQueryable> query); +} \ No newline at end of file diff --git a/Data/Database/Repositories/SubjectRepository.cs b/Data/Database/Repositories/SubjectRepository.cs new file mode 100644 index 0000000..2c2748c --- /dev/null +++ b/Data/Database/Repositories/SubjectRepository.cs @@ -0,0 +1,9 @@ +using System.Linq.Expressions; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Version; + +namespace W542.GandalfReborn.Data.Database.Repositories; + +public class SubjectRepository(ApplicationContext context) : GrRepository(context), ISubjectRepository; + +public interface ISubjectRepository : IGrRepository; \ No newline at end of file diff --git a/Data/Database/Repositories/TokenMetadataRepository.cs b/Data/Database/Repositories/TokenMetadataRepository.cs new file mode 100644 index 0000000..c3e1e67 --- /dev/null +++ b/Data/Database/Repositories/TokenMetadataRepository.cs @@ -0,0 +1,8 @@ + +using W542.GandalfReborn.Data.Entities.Security; + +namespace W542.GandalfReborn.Data.Database.Repositories; + +public class TokenMetadataRepository(ApplicationContext context) : GrRepository(context), ITokenMetadataRepository; + +public interface ITokenMetadataRepository : IGrRepository; \ No newline at end of file diff --git a/Data/Dto/AuthCodeDto.cs b/Data/Dto/AuthCodeDto.cs new file mode 100644 index 0000000..fa8a7f0 --- /dev/null +++ b/Data/Dto/AuthCodeDto.cs @@ -0,0 +1,8 @@ +namespace W542.GandalfReborn.Data.Dto; + +public class AuthCodeDto +{ + public required DateTimeOffset Expiration { get; set; } + public required bool IsRevoked { get; set; } + public required string Code { get; set; } +} \ No newline at end of file diff --git a/Data/Dto/TokenDto.cs b/Data/Dto/TokenDto.cs new file mode 100644 index 0000000..05a8db9 --- /dev/null +++ b/Data/Dto/TokenDto.cs @@ -0,0 +1,7 @@ +namespace W542.GandalfReborn.Data.Dto; + +public class TokenDto +{ + public required string AccessToken { get; set; } + public required string RefreshToken { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/App/AppRelationEntity.cs b/Data/Entities/App/AppRelationEntity.cs new file mode 100644 index 0000000..186eb09 --- /dev/null +++ b/Data/Entities/App/AppRelationEntity.cs @@ -0,0 +1,26 @@ +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Tenant; +using W542.GandalfReborn.Data.Entities.Version; + +namespace W542.GandalfReborn.Data.Entities.App; + +public class AppRelationEntity : AppRelationData, IVersionableEntity +{ + public TenantEntity? Tenant { get; set; } + public HashSet Subjects { get; set; } = []; +} + +public class AppRelationVersionEntity : AppRelationData, IVersionEntity +{ + public SubjectEntity? Suspect { get; set; } + public long SuspectId { get; set; } + public VersionAction Action { get; set; } + public DateTimeOffset At { get; set; } + public AppRelationEntity? Reference { get; set; } +} + +public abstract class AppRelationData : TenantRelationData +{ + public required string Name { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/App/AppSubjectRelationEntity.cs b/Data/Entities/App/AppSubjectRelationEntity.cs new file mode 100644 index 0000000..96c0b2b --- /dev/null +++ b/Data/Entities/App/AppSubjectRelationEntity.cs @@ -0,0 +1,29 @@ +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Security; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Tenant; +using W542.GandalfReborn.Data.Entities.Version; + +namespace W542.GandalfReborn.Data.Entities.App; + +public class AppSubjectRelationEntity : AppSubjectRelationData, IMappingEntity, IVersionableEntity +{ + public HashSet InternalAuthorities { get; set; } = []; + public AppRelationEntity? App { get; set; } + public SubjectEntity? Subject { get; set; } +} + +public class AppSubjectRelationVersionEntity : AppSubjectRelationData, IVersionEntity +{ + public SubjectEntity? Suspect { get; set; } + public long SuspectId { get; set; } + public VersionAction Action { get; set; } + public DateTimeOffset At { get; set; } + public AppSubjectRelationEntity? Reference { get; set; } +} + +public abstract class AppSubjectRelationData where T : IConvertible +{ + public required T AppId { get; set; } + public required T SubjectId { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Base/EntityVisibility.cs b/Data/Entities/Base/EntityVisibility.cs new file mode 100644 index 0000000..187a1ba --- /dev/null +++ b/Data/Entities/Base/EntityVisibility.cs @@ -0,0 +1,9 @@ +namespace W542.GandalfReborn.Data.Entities.Base; + +public enum EntityVisibility +{ + Undefined, + Active, + Draft, + Removed +} \ No newline at end of file diff --git a/Data/Entities/Base/IEntity.cs b/Data/Entities/Base/IEntity.cs new file mode 100644 index 0000000..7055a5e --- /dev/null +++ b/Data/Entities/Base/IEntity.cs @@ -0,0 +1,6 @@ +namespace W542.GandalfReborn.Data.Entities.Base; + +public interface IEntity +{ + long? Id { get; set; } +}; \ No newline at end of file diff --git a/Data/Entities/Base/IMappingEntity.cs b/Data/Entities/Base/IMappingEntity.cs new file mode 100644 index 0000000..247737c --- /dev/null +++ b/Data/Entities/Base/IMappingEntity.cs @@ -0,0 +1,3 @@ +namespace W542.GandalfReborn.Data.Entities.Base; + +public interface IMappingEntity; \ No newline at end of file diff --git a/Data/Entities/Base/IdData.cs b/Data/Entities/Base/IdData.cs new file mode 100644 index 0000000..655c67f --- /dev/null +++ b/Data/Entities/Base/IdData.cs @@ -0,0 +1,6 @@ +namespace W542.GandalfReborn.Data.Entities.Base; + +public abstract class IdData : IEntity +{ + public long? Id { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Base/SubjectData.cs b/Data/Entities/Base/SubjectData.cs new file mode 100644 index 0000000..a816a21 --- /dev/null +++ b/Data/Entities/Base/SubjectData.cs @@ -0,0 +1,6 @@ +namespace W542.GandalfReborn.Data.Entities.Base; + +public abstract class SubjectData : VisibilityData +{ + public long SubjectId { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Base/TenantRelationData.cs b/Data/Entities/Base/TenantRelationData.cs new file mode 100644 index 0000000..d88b9c9 --- /dev/null +++ b/Data/Entities/Base/TenantRelationData.cs @@ -0,0 +1,6 @@ +namespace W542.GandalfReborn.Data.Entities.Base; + +public abstract class TenantRelationData : VisibilityData +{ + public required long TenantId { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Base/VisibilityData.cs b/Data/Entities/Base/VisibilityData.cs new file mode 100644 index 0000000..046bb85 --- /dev/null +++ b/Data/Entities/Base/VisibilityData.cs @@ -0,0 +1,6 @@ +namespace W542.GandalfReborn.Data.Entities.Base; + +public abstract class VisibilityData : IdData +{ + public required EntityVisibility Visibility { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/ContentKeyAttribute.cs b/Data/Entities/ContentKeyAttribute.cs new file mode 100644 index 0000000..a690c3a --- /dev/null +++ b/Data/Entities/ContentKeyAttribute.cs @@ -0,0 +1,6 @@ +namespace W542.GandalfReborn.Data.Entities; + +[AttributeUsage(AttributeTargets.Property)] +public class ContentKeyAttribute : Attribute +{ +} \ No newline at end of file diff --git a/Data/Entities/Security/AppUserRelationInternalAuthorityRelationEntity.cs b/Data/Entities/Security/AppUserRelationInternalAuthorityRelationEntity.cs new file mode 100644 index 0000000..fee4a4c --- /dev/null +++ b/Data/Entities/Security/AppUserRelationInternalAuthorityRelationEntity.cs @@ -0,0 +1,29 @@ +using W542.GandalfReborn.Data.Entities.App; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Tenant; +using W542.GandalfReborn.Data.Entities.Version; + +namespace W542.GandalfReborn.Data.Entities.Security; + +public class AppSubjectRelationInternalAuthorityRelationEntity : AppSubjectRelationInternalAuthorityRelationData, IMappingEntity, IVersionableEntity +{ + public AppSubjectRelationEntity? AppSubjectRelation { get; set; } + public AuthorityEntity? InternalAuthority { get; set; } +} + +public class AppSubjectRelationInternalAuthorityRelationVersionEntity : AppSubjectRelationInternalAuthorityRelationData, IVersionEntity +{ + public SubjectEntity? Suspect { get; set; } + public long SuspectId { get; set; } + public VersionAction Action { get; set; } + public DateTimeOffset At { get; set; } + public AppSubjectRelationInternalAuthorityRelationEntity? Reference { get; set; } +} + +public class AppSubjectRelationInternalAuthorityRelationData where T : IConvertible +{ + public required T AppId { get; set; } + public required T SubjectId { get; set; } + public required T InternalAuthorityId { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Security/AuthCodeEntity.cs b/Data/Entities/Security/AuthCodeEntity.cs new file mode 100644 index 0000000..1c43b02 --- /dev/null +++ b/Data/Entities/Security/AuthCodeEntity.cs @@ -0,0 +1,13 @@ +using W542.GandalfReborn.Data.Entities.Base; + +namespace W542.GandalfReborn.Data.Entities.Security; + +public class AuthCodeEntity : IdData +{ + public required long SubjectId { get; set; } + public required DateTimeOffset Expiration { get; set; } + public required bool IsRevoked { get; set; } + public required string Code { get; set; } + public required string Challenge { get; set; } + public required string Algorithm { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Security/AuthorityEntity.cs b/Data/Entities/Security/AuthorityEntity.cs new file mode 100644 index 0000000..a88d8d0 --- /dev/null +++ b/Data/Entities/Security/AuthorityEntity.cs @@ -0,0 +1,27 @@ +using W542.GandalfReborn.Data.Entities.App; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Tenant; + +namespace W542.GandalfReborn.Data.Entities.Security; + +public class AuthorityEntity : IdData +{ + public required string Name { get; set; } + + public required AuthorityType Type { get; set; } + + [ContentKey] public string? Description { get; set; } + + public HashSet? TenantSubjectRelations { get; set; } = []; + public HashSet? AppSubjectRelations { get; set; } = []; +} + +public static class TenantAuthority +{ + public const string Read = "Tenant_Read"; +} + +public static class AppAuthority +{ + public const string Read = "App_Read"; +} \ No newline at end of file diff --git a/Data/Entities/Security/AuthorityType.cs b/Data/Entities/Security/AuthorityType.cs new file mode 100644 index 0000000..b635b58 --- /dev/null +++ b/Data/Entities/Security/AuthorityType.cs @@ -0,0 +1,7 @@ +namespace W542.GandalfReborn.Data.Entities.Security; + +public enum AuthorityType +{ + Tenant, + App +} \ No newline at end of file diff --git a/Data/Entities/Security/TenantSubjectRelationInternalAuthorityRelationEntity.cs b/Data/Entities/Security/TenantSubjectRelationInternalAuthorityRelationEntity.cs new file mode 100644 index 0000000..e8f4f97 --- /dev/null +++ b/Data/Entities/Security/TenantSubjectRelationInternalAuthorityRelationEntity.cs @@ -0,0 +1,28 @@ +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Tenant; +using W542.GandalfReborn.Data.Entities.Version; + +namespace W542.GandalfReborn.Data.Entities.Security; + +public class TenantSubjectRelationInternalAuthorityRelationEntity : TenantSubjectRelationInternalAuthorityRelationData, IMappingEntity, IVersionableEntity +{ + public TenantSubjectRelationEntity? TenantSubjectRelation { get; set; } + public AuthorityEntity? InternalAuthority { get; set; } +} + +public class TenantSubjectRelationInternalAuthorityRelationVersionEntity : TenantSubjectRelationInternalAuthorityRelationData, IVersionEntity +{ + public SubjectEntity? Suspect { get; set; } + public long SuspectId { get; set; } + public VersionAction Action { get; set; } + public DateTimeOffset At { get; set; } + public TenantSubjectRelationInternalAuthorityRelationEntity? Reference { get; set; } +} + +public class TenantSubjectRelationInternalAuthorityRelationData where T : IConvertible +{ + public required T TenantId { get; set; } + public required T SubjectId { get; set; } + public required T InternalAuthorityId { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Security/TokenMetaDataEntity.cs b/Data/Entities/Security/TokenMetaDataEntity.cs new file mode 100644 index 0000000..7679fec --- /dev/null +++ b/Data/Entities/Security/TokenMetaDataEntity.cs @@ -0,0 +1,14 @@ +using W542.GandalfReborn.Data.Entities.App; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Tenant; + +namespace W542.GandalfReborn.Data.Entities.Security; + +public class TokenMetadataEntity : IdData +{ + public required DateTimeOffset Expiration { get; set; } + public required bool IsRevoked { get; set; } + public required TokenType TokenType { get; set; } + public required long UsedBy { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Security/TokenType.cs b/Data/Entities/Security/TokenType.cs new file mode 100644 index 0000000..6f2285d --- /dev/null +++ b/Data/Entities/Security/TokenType.cs @@ -0,0 +1,7 @@ +namespace W542.GandalfReborn.Data.Entities.Security; + +public enum TokenType +{ + Application, + User +} \ No newline at end of file diff --git a/Data/Entities/Subject/SignIn/SignInEntity.cs b/Data/Entities/Subject/SignIn/SignInEntity.cs new file mode 100644 index 0000000..25e4964 --- /dev/null +++ b/Data/Entities/Subject/SignIn/SignInEntity.cs @@ -0,0 +1,12 @@ +using W542.GandalfReborn.Data.Entities.Base; + +namespace W542.GandalfReborn.Data.Entities.Subject.SignIn; + +public class SignInEntity : SubjectData +{ + public required SignInMethod Method { get; set; } + public required bool IsLegacy { get; set; } + public string? Email { get; set; } + public string? PasswordHash { get; set; } + public SubjectEntity? Subject { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Subject/SignIn/SignInMethod.cs b/Data/Entities/Subject/SignIn/SignInMethod.cs new file mode 100644 index 0000000..851ee44 --- /dev/null +++ b/Data/Entities/Subject/SignIn/SignInMethod.cs @@ -0,0 +1,8 @@ +namespace W542.GandalfReborn.Data.Entities.Subject.SignIn; + +public enum SignInMethod +{ + Simple, + Google, + Steam +} \ No newline at end of file diff --git a/Data/Entities/Subject/SubjectEntity.cs b/Data/Entities/Subject/SubjectEntity.cs new file mode 100644 index 0000000..b869d5c --- /dev/null +++ b/Data/Entities/Subject/SubjectEntity.cs @@ -0,0 +1,14 @@ +using W542.GandalfReborn.Data.Entities.App; +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Subject.SignIn; +using W542.GandalfReborn.Data.Entities.Tenant; + +namespace W542.GandalfReborn.Data.Entities.Subject; + +public class SubjectEntity : VisibilityData +{ + public required string Name { get; set; } + public HashSet SignInMethods { get; set; } = []; + public HashSet Tenants { get; set; } = []; + public HashSet Apps { get; set; } = []; +} \ No newline at end of file diff --git a/Data/Entities/Tenant/OwnerData.cs b/Data/Entities/Tenant/OwnerData.cs new file mode 100644 index 0000000..3319af7 --- /dev/null +++ b/Data/Entities/Tenant/OwnerData.cs @@ -0,0 +1,8 @@ +using W542.GandalfReborn.Data.Entities.Base; + +namespace W542.GandalfReborn.Data.Entities.Tenant; + +public abstract class OwnerData : VisibilityData +{ + public required long OwnerId { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Tenant/TenantEntity.cs b/Data/Entities/Tenant/TenantEntity.cs new file mode 100644 index 0000000..92fe97c --- /dev/null +++ b/Data/Entities/Tenant/TenantEntity.cs @@ -0,0 +1,28 @@ +using W542.GandalfReborn.Data.Entities.App; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Version; + +namespace W542.GandalfReborn.Data.Entities.Tenant; + +public class TenantEntity : TenantData, IVersionableEntity +{ + public SubjectEntity? Owner { get; set; } + public HashSet Subjects { get; set; } = []; + public HashSet Apps { get; set; } = []; +} + +public interface IVersionableEntity; + +public class TenantVersionEntity : TenantData, IVersionEntity +{ + public SubjectEntity? Suspect { get; set; } + public long SuspectId { get; set; } + public VersionAction Action { get; set; } + public DateTimeOffset At { get; set; } + public TenantEntity? Reference { get; set; } +} + +public abstract class TenantData : OwnerData +{ + public required string Name { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Tenant/TenantSubjectRelationEntity.cs b/Data/Entities/Tenant/TenantSubjectRelationEntity.cs new file mode 100644 index 0000000..c9d1a52 --- /dev/null +++ b/Data/Entities/Tenant/TenantSubjectRelationEntity.cs @@ -0,0 +1,28 @@ +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Security; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Version; + +namespace W542.GandalfReborn.Data.Entities.Tenant; + +public class TenantSubjectRelationEntity : TenantSubjectRelationData, IMappingEntity, IVersionableEntity +{ + public TenantEntity? Tenant { get; set; } + public SubjectEntity? Subject { get; set; } + public HashSet InternalAuthorities { get; set; } = []; +} + +public class TenantSubjectRelationVersionEntity : TenantSubjectRelationData, IVersionEntity +{ + public SubjectEntity? Suspect { get; set; } + public long SuspectId { get; set; } + public VersionAction Action { get; set; } + public DateTimeOffset At { get; set; } + public TenantSubjectRelationEntity? Reference { get; set; } +} + +public abstract class TenantSubjectRelationData where T : IConvertible +{ + public T TenantId { get; set; } + public T SubjectId { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Version/IVersionEntity.cs b/Data/Entities/Version/IVersionEntity.cs new file mode 100644 index 0000000..9cfd41b --- /dev/null +++ b/Data/Entities/Version/IVersionEntity.cs @@ -0,0 +1,18 @@ +using W542.GandalfReborn.Data.Entities.Base; +using W542.GandalfReborn.Data.Entities.Subject; +using W542.GandalfReborn.Data.Entities.Tenant; + +namespace W542.GandalfReborn.Data.Entities.Version; + +public interface IVersionableBase : IEntity, IVersionableEntity; + +public interface IVersionEntity : IVersionEntity; + +public interface IVersionEntity where T : IVersionableEntity +{ + public SubjectEntity? Suspect { get; set; } + public long SuspectId { get; set; } + public VersionAction Action { get; set; } + public DateTimeOffset At { get; set; } + public T? Reference { get; set; } +} \ No newline at end of file diff --git a/Data/Entities/Version/VersionAction.cs b/Data/Entities/Version/VersionAction.cs new file mode 100644 index 0000000..fa17e4a --- /dev/null +++ b/Data/Entities/Version/VersionAction.cs @@ -0,0 +1,9 @@ +namespace W542.GandalfReborn.Data.Entities.Version; + +public enum VersionAction +{ + Unknown, + Created, + Modified, + Deleted +} \ No newline at end of file diff --git a/Data/Extensions/StringExtensions.cs b/Data/Extensions/StringExtensions.cs new file mode 100644 index 0000000..30fe37a --- /dev/null +++ b/Data/Extensions/StringExtensions.cs @@ -0,0 +1,37 @@ +using System.Text; + +namespace W542.GandalfReborn.Data.Extensions; + +public static class StringExtensions +{ + public static string ToSnakeCase(this string text) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); + } + + if (text.Length < 2) + { + return text.ToLowerInvariant(); + } + + var sb = new StringBuilder(); + sb.Append(char.ToLowerInvariant(text[0])); + for (int i = 1; i < text.Length; ++i) + { + char c = text[i]; + if (char.IsUpper(c)) + { + sb.Append('_'); + sb.Append(char.ToLowerInvariant(c)); + } + else + { + sb.Append(c); + } + } + + return sb.ToString(); + } +} \ No newline at end of file diff --git a/Data/Mapper/AuthCodeDtoMappingProfile.cs b/Data/Mapper/AuthCodeDtoMappingProfile.cs new file mode 100644 index 0000000..88562c6 --- /dev/null +++ b/Data/Mapper/AuthCodeDtoMappingProfile.cs @@ -0,0 +1,13 @@ +using AutoMapper; +using W542.GandalfReborn.Data.Dto; +using W542.GandalfReborn.Data.Entities.Security; + +namespace W542.GandalfReborn.Data.Mapper; + +public class AuthCodeDtoMappingProfile : Profile +{ + public AuthCodeDtoMappingProfile() + { + CreateMap(); + } +} \ No newline at end of file diff --git a/Data/Migrations/20240903154112_sus.Designer.cs b/Data/Migrations/20240903154112_sus.Designer.cs new file mode 100644 index 0000000..a7e667b --- /dev/null +++ b/Data/Migrations/20240903154112_sus.Designer.cs @@ -0,0 +1,663 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240903154112_sus")] + partial class sus + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240903154112_sus.cs b/Data/Migrations/20240903154112_sus.cs new file mode 100644 index 0000000..c2781fc --- /dev/null +++ b/Data/Migrations/20240903154112_sus.cs @@ -0,0 +1,592 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class sus : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "gr"); + + migrationBuilder.CreateTable( + name: "Authority", + schema: "gr", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false), + Type = table.Column(type: "text", nullable: false), + Description = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Authority", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Subject", + schema: "gr", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false), + Visibility = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Subject", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "SignIn", + schema: "gr", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Method = table.Column(type: "text", nullable: false), + IsLegacy = table.Column(type: "boolean", nullable: false), + Email = table.Column(type: "text", nullable: true), + PasswordHash = table.Column(type: "text", nullable: true), + Visibility = table.Column(type: "text", nullable: false), + SubjectId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SignIn", x => x.Id); + table.ForeignKey( + name: "FK_SignIn_Subject_SubjectId", + column: x => x.SubjectId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Tenant", + schema: "gr", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Visibility = table.Column(type: "text", nullable: false), + OwnerId = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tenant", x => x.Id); + table.ForeignKey( + name: "FK_Tenant_Subject_OwnerId", + column: x => x.OwnerId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AppRelation", + schema: "gr", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Visibility = table.Column(type: "text", nullable: false), + TenantId = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppRelation", x => x.Id); + table.ForeignKey( + name: "FK_AppRelation_Tenant_TenantId", + column: x => x.TenantId, + principalSchema: "gr", + principalTable: "Tenant", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TenantSubjectRelation", + schema: "gr", + columns: table => new + { + TenantId = table.Column(type: "bigint", nullable: false), + SubjectId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TenantSubjectRelation", x => new { x.SubjectId, x.TenantId }); + table.ForeignKey( + name: "FK_TenantSubjectRelation_Subject_SubjectId", + column: x => x.SubjectId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TenantSubjectRelation_Tenant_TenantId", + column: x => x.TenantId, + principalSchema: "gr", + principalTable: "Tenant", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TenantVersion", + schema: "gr", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false), + At = table.Column(type: "timestamp with time zone", nullable: false), + SuspectId = table.Column(type: "bigint", nullable: false), + Action = table.Column(type: "text", nullable: false), + Visibility = table.Column(type: "text", nullable: false), + OwnerId = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TenantVersion", x => new { x.Id, x.At }); + table.ForeignKey( + name: "FK_TenantVersion_Subject_SuspectId", + column: x => x.SuspectId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TenantVersion_Tenant_Id", + column: x => x.Id, + principalSchema: "gr", + principalTable: "Tenant", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AppRelationVersion", + schema: "gr", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false), + At = table.Column(type: "timestamp with time zone", nullable: false), + SuspectId = table.Column(type: "bigint", nullable: false), + Action = table.Column(type: "text", nullable: false), + Visibility = table.Column(type: "text", nullable: false), + TenantId = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppRelationVersion", x => new { x.Id, x.At }); + table.ForeignKey( + name: "FK_AppRelationVersion_AppRelation_Id", + column: x => x.Id, + principalSchema: "gr", + principalTable: "AppRelation", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AppRelationVersion_Subject_SuspectId", + column: x => x.SuspectId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AppSubjectRelation", + schema: "gr", + columns: table => new + { + AppId = table.Column(type: "bigint", nullable: false), + SubjectId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppSubjectRelation", x => new { x.SubjectId, x.AppId }); + table.ForeignKey( + name: "FK_AppSubjectRelation_AppRelation_AppId", + column: x => x.AppId, + principalSchema: "gr", + principalTable: "AppRelation", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AppSubjectRelation_Subject_SubjectId", + column: x => x.SubjectId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TenantSubjectRelationInternalAuthorityRelation", + schema: "gr", + columns: table => new + { + TenantId = table.Column(type: "bigint", nullable: false), + SubjectId = table.Column(type: "bigint", nullable: false), + InternalAuthorityId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TenantSubjectRelationInternalAuthorityRelation", x => new { x.SubjectId, x.TenantId, x.InternalAuthorityId }); + table.ForeignKey( + name: "FK_TenantSubjectRelationInternalAuthorityRelation_Authority_In~", + column: x => x.InternalAuthorityId, + principalSchema: "gr", + principalTable: "Authority", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TenantSubjectRelationInternalAuthorityRelation_TenantSubjec~", + columns: x => new { x.SubjectId, x.TenantId }, + principalSchema: "gr", + principalTable: "TenantSubjectRelation", + principalColumns: new[] { "SubjectId", "TenantId" }, + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TenantSubjectRelationVersion", + schema: "gr", + columns: table => new + { + TenantId = table.Column(type: "bigint", nullable: false), + SubjectId = table.Column(type: "bigint", nullable: false), + At = table.Column(type: "timestamp with time zone", nullable: false), + SuspectId = table.Column(type: "bigint", nullable: false), + Action = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TenantSubjectRelationVersion", x => new { x.SubjectId, x.TenantId, x.At }); + table.ForeignKey( + name: "FK_TenantSubjectRelationVersion_Subject_SuspectId", + column: x => x.SuspectId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TenantSubjectRelationVersion_TenantSubjectRelation_SubjectI~", + columns: x => new { x.SubjectId, x.TenantId }, + principalSchema: "gr", + principalTable: "TenantSubjectRelation", + principalColumns: new[] { "SubjectId", "TenantId" }, + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AppSubjectRelationInternalAuthorityRelation", + schema: "gr", + columns: table => new + { + AppId = table.Column(type: "bigint", nullable: false), + SubjectId = table.Column(type: "bigint", nullable: false), + InternalAuthorityId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppSubjectRelationInternalAuthorityRelation", x => new { x.SubjectId, x.AppId, x.InternalAuthorityId }); + table.ForeignKey( + name: "FK_AppSubjectRelationInternalAuthorityRelation_AppSubjectRelat~", + columns: x => new { x.SubjectId, x.AppId }, + principalSchema: "gr", + principalTable: "AppSubjectRelation", + principalColumns: new[] { "SubjectId", "AppId" }, + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AppSubjectRelationInternalAuthorityRelation_Authority_Inter~", + column: x => x.InternalAuthorityId, + principalSchema: "gr", + principalTable: "Authority", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AppSubjectRelationVersion", + schema: "gr", + columns: table => new + { + AppId = table.Column(type: "bigint", nullable: false), + SubjectId = table.Column(type: "bigint", nullable: false), + At = table.Column(type: "timestamp with time zone", nullable: false), + SuspectId = table.Column(type: "bigint", nullable: false), + Action = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppSubjectRelationVersion", x => new { x.SubjectId, x.AppId, x.At }); + table.ForeignKey( + name: "FK_AppSubjectRelationVersion_AppSubjectRelation_SubjectId_AppId", + columns: x => new { x.SubjectId, x.AppId }, + principalSchema: "gr", + principalTable: "AppSubjectRelation", + principalColumns: new[] { "SubjectId", "AppId" }, + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AppSubjectRelationVersion_Subject_SuspectId", + column: x => x.SuspectId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TenantSubjectRelationInternalAuthorityRelationVersion", + schema: "gr", + columns: table => new + { + TenantId = table.Column(type: "bigint", nullable: false), + SubjectId = table.Column(type: "bigint", nullable: false), + InternalAuthorityId = table.Column(type: "bigint", nullable: false), + At = table.Column(type: "timestamp with time zone", nullable: false), + SuspectId = table.Column(type: "bigint", nullable: false), + Action = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TenantSubjectRelationInternalAuthorityRelationVersion", x => new { x.SubjectId, x.TenantId, x.InternalAuthorityId, x.At }); + table.ForeignKey( + name: "FK_TenantSubjectRelationInternalAuthorityRelationVersion_Subje~", + column: x => x.SuspectId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TenantSubjectRelationInternalAuthorityRelationVersion_Tenan~", + columns: x => new { x.SubjectId, x.TenantId, x.InternalAuthorityId }, + principalSchema: "gr", + principalTable: "TenantSubjectRelationInternalAuthorityRelation", + principalColumns: new[] { "SubjectId", "TenantId", "InternalAuthorityId" }, + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AppSubjectRelationInternalAuthorityRelationVersion", + schema: "gr", + columns: table => new + { + AppId = table.Column(type: "bigint", nullable: false), + SubjectId = table.Column(type: "bigint", nullable: false), + InternalAuthorityId = table.Column(type: "bigint", nullable: false), + At = table.Column(type: "timestamp with time zone", nullable: false), + SuspectId = table.Column(type: "bigint", nullable: false), + Action = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppSubjectRelationInternalAuthorityRelationVersion", x => new { x.SubjectId, x.AppId, x.InternalAuthorityId, x.At }); + table.ForeignKey( + name: "FK_AppSubjectRelationInternalAuthorityRelationVersion_AppSubje~", + columns: x => new { x.SubjectId, x.AppId, x.InternalAuthorityId }, + principalSchema: "gr", + principalTable: "AppSubjectRelationInternalAuthorityRelation", + principalColumns: new[] { "SubjectId", "AppId", "InternalAuthorityId" }, + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AppSubjectRelationInternalAuthorityRelationVersion_Subject_~", + column: x => x.SuspectId, + principalSchema: "gr", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + schema: "gr", + table: "Authority", + columns: new[] { "Id", "Description", "Name", "Type" }, + values: new object[,] + { + { 1L, "Allows users to read tenants", "Tenant_Read", "Tenant" }, + { 2L, "Allows users to read apps", "App_Read", "App" } + }); + + migrationBuilder.InsertData( + schema: "gr", + table: "Subject", + columns: new[] { "Id", "Name", "Visibility" }, + values: new object[] { 1L, "chris", "Active" }); + + migrationBuilder.CreateIndex( + name: "IX_AppRelation_TenantId", + schema: "gr", + table: "AppRelation", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_AppRelationVersion_SuspectId", + schema: "gr", + table: "AppRelationVersion", + column: "SuspectId"); + + migrationBuilder.CreateIndex( + name: "IX_AppSubjectRelation_AppId", + schema: "gr", + table: "AppSubjectRelation", + column: "AppId"); + + migrationBuilder.CreateIndex( + name: "IX_AppSubjectRelationInternalAuthorityRelation_InternalAuthori~", + schema: "gr", + table: "AppSubjectRelationInternalAuthorityRelation", + column: "InternalAuthorityId"); + + migrationBuilder.CreateIndex( + name: "IX_AppSubjectRelationInternalAuthorityRelationVersion_SuspectId", + schema: "gr", + table: "AppSubjectRelationInternalAuthorityRelationVersion", + column: "SuspectId"); + + migrationBuilder.CreateIndex( + name: "IX_AppSubjectRelationVersion_SuspectId", + schema: "gr", + table: "AppSubjectRelationVersion", + column: "SuspectId"); + + migrationBuilder.CreateIndex( + name: "IX_Authority_Name", + schema: "gr", + table: "Authority", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_SignIn_SubjectId", + schema: "gr", + table: "SignIn", + column: "SubjectId"); + + migrationBuilder.CreateIndex( + name: "IX_Subject_Name", + schema: "gr", + table: "Subject", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Tenant_OwnerId", + schema: "gr", + table: "Tenant", + column: "OwnerId"); + + migrationBuilder.CreateIndex( + name: "IX_TenantSubjectRelation_TenantId", + schema: "gr", + table: "TenantSubjectRelation", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_TenantSubjectRelationInternalAuthorityRelation_InternalAuth~", + schema: "gr", + table: "TenantSubjectRelationInternalAuthorityRelation", + column: "InternalAuthorityId"); + + migrationBuilder.CreateIndex( + name: "IX_TenantSubjectRelationInternalAuthorityRelationVersion_Suspe~", + schema: "gr", + table: "TenantSubjectRelationInternalAuthorityRelationVersion", + column: "SuspectId"); + + migrationBuilder.CreateIndex( + name: "IX_TenantSubjectRelationVersion_SuspectId", + schema: "gr", + table: "TenantSubjectRelationVersion", + column: "SuspectId"); + + migrationBuilder.CreateIndex( + name: "IX_TenantVersion_SuspectId", + schema: "gr", + table: "TenantVersion", + column: "SuspectId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AppRelationVersion", + schema: "gr"); + + migrationBuilder.DropTable( + name: "AppSubjectRelationInternalAuthorityRelationVersion", + schema: "gr"); + + migrationBuilder.DropTable( + name: "AppSubjectRelationVersion", + schema: "gr"); + + migrationBuilder.DropTable( + name: "SignIn", + schema: "gr"); + + migrationBuilder.DropTable( + name: "TenantSubjectRelationInternalAuthorityRelationVersion", + schema: "gr"); + + migrationBuilder.DropTable( + name: "TenantSubjectRelationVersion", + schema: "gr"); + + migrationBuilder.DropTable( + name: "TenantVersion", + schema: "gr"); + + migrationBuilder.DropTable( + name: "AppSubjectRelationInternalAuthorityRelation", + schema: "gr"); + + migrationBuilder.DropTable( + name: "TenantSubjectRelationInternalAuthorityRelation", + schema: "gr"); + + migrationBuilder.DropTable( + name: "AppSubjectRelation", + schema: "gr"); + + migrationBuilder.DropTable( + name: "Authority", + schema: "gr"); + + migrationBuilder.DropTable( + name: "TenantSubjectRelation", + schema: "gr"); + + migrationBuilder.DropTable( + name: "AppRelation", + schema: "gr"); + + migrationBuilder.DropTable( + name: "Tenant", + schema: "gr"); + + migrationBuilder.DropTable( + name: "Subject", + schema: "gr"); + } + } +} diff --git a/Data/Migrations/20240914003536_addTokens.Designer.cs b/Data/Migrations/20240914003536_addTokens.Designer.cs new file mode 100644 index 0000000..dc45b38 --- /dev/null +++ b/Data/Migrations/20240914003536_addTokens.Designer.cs @@ -0,0 +1,716 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240914003536_addTokens")] + partial class addTokens + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240914003536_addTokens.cs b/Data/Migrations/20240914003536_addTokens.cs new file mode 100644 index 0000000..62e8994 --- /dev/null +++ b/Data/Migrations/20240914003536_addTokens.cs @@ -0,0 +1,62 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class addTokens : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AuthCode", + schema: "gr", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Expiration = table.Column(type: "timestamp with time zone", nullable: false), + IsRevoked = table.Column(type: "boolean", nullable: false), + Code = table.Column(type: "text", nullable: false), + Challenge = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AuthCode", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "TokenMetadata", + schema: "gr", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Expiration = table.Column(type: "timestamp with time zone", nullable: false), + IsRevoked = table.Column(type: "boolean", nullable: false), + TokenType = table.Column(type: "text", nullable: false), + UsedBy = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TokenMetadata", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AuthCode", + schema: "gr"); + + migrationBuilder.DropTable( + name: "TokenMetadata", + schema: "gr"); + } + } +} diff --git a/Data/Migrations/20240914005530_affwaf.Designer.cs b/Data/Migrations/20240914005530_affwaf.Designer.cs new file mode 100644 index 0000000..92a08ef --- /dev/null +++ b/Data/Migrations/20240914005530_affwaf.Designer.cs @@ -0,0 +1,716 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240914005530_affwaf")] + partial class affwaf + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240914005530_affwaf.cs b/Data/Migrations/20240914005530_affwaf.cs new file mode 100644 index 0000000..7ef1222 --- /dev/null +++ b/Data/Migrations/20240914005530_affwaf.cs @@ -0,0 +1,173 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class affwaf : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "TokenMetadata", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Tenant", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Subject", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "SignIn", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Authority", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "AuthCode", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "AppRelation", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "TokenMetadata", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Tenant", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Subject", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "SignIn", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Authority", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "AuthCode", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "AppRelation", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + } + } +} diff --git a/Data/Migrations/20240914012943_fawfghh.Designer.cs b/Data/Migrations/20240914012943_fawfghh.Designer.cs new file mode 100644 index 0000000..9ff207e --- /dev/null +++ b/Data/Migrations/20240914012943_fawfghh.Designer.cs @@ -0,0 +1,716 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240914012943_fawfghh")] + partial class fawfghh + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240914012943_fawfghh.cs b/Data/Migrations/20240914012943_fawfghh.cs new file mode 100644 index 0000000..6c5a9bf --- /dev/null +++ b/Data/Migrations/20240914012943_fawfghh.cs @@ -0,0 +1,173 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class fawfghh : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "TokenMetadata", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Tenant", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Subject", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "SignIn", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Authority", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "AuthCode", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "AppRelation", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "TokenMetadata", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Tenant", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Subject", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "SignIn", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "Authority", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "AuthCode", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.AlterColumn( + name: "Id", + schema: "gr", + table: "AppRelation", + type: "bigint", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn) + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + } + } +} diff --git a/Data/Migrations/20240914014850_gjjjjjj.Designer.cs b/Data/Migrations/20240914014850_gjjjjjj.Designer.cs new file mode 100644 index 0000000..c7ce509 --- /dev/null +++ b/Data/Migrations/20240914014850_gjjjjjj.Designer.cs @@ -0,0 +1,716 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240914014850_gjjjjjj")] + partial class gjjjjjj + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240914014850_gjjjjjj.cs b/Data/Migrations/20240914014850_gjjjjjj.cs new file mode 100644 index 0000000..e289962 --- /dev/null +++ b/Data/Migrations/20240914014850_gjjjjjj.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class gjjjjjj : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/Data/Migrations/20240914224344_jsoikgsoieg.Designer.cs b/Data/Migrations/20240914224344_jsoikgsoieg.Designer.cs new file mode 100644 index 0000000..afcf717 --- /dev/null +++ b/Data/Migrations/20240914224344_jsoikgsoieg.Designer.cs @@ -0,0 +1,719 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240914224344_jsoikgsoieg")] + partial class jsoikgsoieg + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240914224344_jsoikgsoieg.cs b/Data/Migrations/20240914224344_jsoikgsoieg.cs new file mode 100644 index 0000000..05241a5 --- /dev/null +++ b/Data/Migrations/20240914224344_jsoikgsoieg.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class jsoikgsoieg : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateIndex( + name: "IX_SignIn_Email", + schema: "gr", + table: "SignIn", + column: "Email", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_SignIn_Email", + schema: "gr", + table: "SignIn"); + } + } +} diff --git a/Data/Migrations/20240919005908_afwawfawf.Designer.cs b/Data/Migrations/20240919005908_afwawfawf.Designer.cs new file mode 100644 index 0000000..97c6a34 --- /dev/null +++ b/Data/Migrations/20240919005908_afwawfawf.Designer.cs @@ -0,0 +1,730 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240919005908_afwawfawf")] + partial class afwawfawf + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Temp.TempInvokerContextEntity", b => + { + b.Property("SubjectId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("SubjectId"); + + b.ToTable("TempInvokerContext", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240919005908_afwawfawf.cs b/Data/Migrations/20240919005908_afwawfawf.cs new file mode 100644 index 0000000..9f599e8 --- /dev/null +++ b/Data/Migrations/20240919005908_afwawfawf.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class afwawfawf : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "TempInvokerContext", + schema: "gr", + columns: table => new + { + SubjectId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TempInvokerContext", x => x.SubjectId); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "TempInvokerContext", + schema: "gr"); + } + } +} diff --git a/Data/Migrations/20240919010339_ffffff.Designer.cs b/Data/Migrations/20240919010339_ffffff.Designer.cs new file mode 100644 index 0000000..4472e37 --- /dev/null +++ b/Data/Migrations/20240919010339_ffffff.Designer.cs @@ -0,0 +1,729 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240919010339_ffffff")] + partial class ffffff + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Temp.TempInvokerContextEntity", b => + { + b.Property("SubjectId") + .HasColumnType("uuid"); + + b.ToTable("TempInvokerContext", "gr"); + + b.ToView("#TempInvokerContext", (string)null); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240919010339_ffffff.cs b/Data/Migrations/20240919010339_ffffff.cs new file mode 100644 index 0000000..8652e18 --- /dev/null +++ b/Data/Migrations/20240919010339_ffffff.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class ffffff : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_TempInvokerContext", + schema: "gr", + table: "TempInvokerContext"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddPrimaryKey( + name: "PK_TempInvokerContext", + schema: "gr", + table: "TempInvokerContext", + column: "SubjectId"); + } + } +} diff --git a/Data/Migrations/20240919010748_jm├ñpromh.Designer.cs b/Data/Migrations/20240919010748_jm├ñpromh.Designer.cs new file mode 100644 index 0000000..24890b7 --- /dev/null +++ b/Data/Migrations/20240919010748_jm├ñpromh.Designer.cs @@ -0,0 +1,730 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240919010748_jm├ñpromh")] + partial class jmñpromh + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Temp.TempInvokerContextEntity", b => + { + b.Property("SubjectId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("SubjectId"); + + b.ToTable("TempInvokerContext", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240919010748_jm├ñpromh.cs b/Data/Migrations/20240919010748_jm├ñpromh.cs new file mode 100644 index 0000000..fe216d8 --- /dev/null +++ b/Data/Migrations/20240919010748_jm├ñpromh.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class jmñpromh : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddPrimaryKey( + name: "PK_TempInvokerContext", + schema: "gr", + table: "TempInvokerContext", + column: "SubjectId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_TempInvokerContext", + schema: "gr", + table: "TempInvokerContext"); + } + } +} diff --git a/Data/Migrations/20240919012025_fghdhhzttr.Designer.cs b/Data/Migrations/20240919012025_fghdhhzttr.Designer.cs new file mode 100644 index 0000000..d43bdb9 --- /dev/null +++ b/Data/Migrations/20240919012025_fghdhhzttr.Designer.cs @@ -0,0 +1,719 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240919012025_fghdhhzttr")] + partial class fghdhhzttr + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240919012025_fghdhhzttr.cs b/Data/Migrations/20240919012025_fghdhhzttr.cs new file mode 100644 index 0000000..d01d1b3 --- /dev/null +++ b/Data/Migrations/20240919012025_fghdhhzttr.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class fghdhhzttr : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "TempInvokerContext", + schema: "gr"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "TempInvokerContext", + schema: "gr", + columns: table => new + { + SubjectId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TempInvokerContext", x => x.SubjectId); + }); + } + } +} diff --git a/Data/Migrations/20240921214234_kl├╢hmpdmpmgr.Designer.cs b/Data/Migrations/20240921214234_kl├╢hmpdmpmgr.Designer.cs new file mode 100644 index 0000000..7cc5e45 --- /dev/null +++ b/Data/Migrations/20240921214234_kl├╢hmpdmpmgr.Designer.cs @@ -0,0 +1,726 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20240921214234_kl├╢hmpdmpmgr")] + partial class klhmpdmpmgr + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Algorithm") + .IsRequired() + .HasColumnType("text"); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20240921214234_kl├╢hmpdmpmgr.cs b/Data/Migrations/20240921214234_kl├╢hmpdmpmgr.cs new file mode 100644 index 0000000..d8a7900 --- /dev/null +++ b/Data/Migrations/20240921214234_kl├╢hmpdmpmgr.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + /// + public partial class klhmpdmpmgr : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Algorithm", + schema: "gr", + table: "AuthCode", + type: "text", + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "SubjectId", + schema: "gr", + table: "AuthCode", + type: "bigint", + nullable: false, + defaultValue: 0L); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Algorithm", + schema: "gr", + table: "AuthCode"); + + migrationBuilder.DropColumn( + name: "SubjectId", + schema: "gr", + table: "AuthCode"); + } + } +} diff --git a/Data/Migrations/ApplicationContextModelSnapshot.cs b/Data/Migrations/ApplicationContextModelSnapshot.cs new file mode 100644 index 0000000..b3e12d1 --- /dev/null +++ b/Data/Migrations/ApplicationContextModelSnapshot.cs @@ -0,0 +1,723 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using W542.GandalfReborn.Data.Database; + +#nullable disable + +namespace W542.GandalfReborn.Data.Migrations +{ + [DbContext(typeof(ApplicationContext))] + partial class ApplicationContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("AppRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId"); + + b.HasIndex("AppId"); + + b.ToTable("AppSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("AppId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "AppId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("AppSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthCodeEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Algorithm") + .IsRequired() + .HasColumnType("text"); + + b.Property("Challenge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuthCode", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Authority", "gr"); + + b.HasData( + new + { + Id = 1L, + Description = "Allows users to read tenants", + Name = "Tenant_Read", + Type = "Tenant" + }, + new + { + Id = 2L, + Description = "Allows users to read apps", + Name = "App_Read", + Type = "App" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId"); + + b.HasIndex("InternalAuthorityId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("InternalAuthorityId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "InternalAuthorityId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationInternalAuthorityRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TokenMetadataEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("TokenType") + .IsRequired() + .HasColumnType("text"); + + b.Property("UsedBy") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("TokenMetadata", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsLegacy") + .HasColumnType("boolean"); + + b.Property("Method") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("SubjectId"); + + b.ToTable("SignIn", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Subject", "gr"); + + b.HasData( + new + { + Id = 1L, + Name = "chris", + Visibility = "Active" + }); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Tenant", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantSubjectRelation", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.Property("SubjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.HasKey("SubjectId", "TenantId", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantSubjectRelationVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("At") + .HasColumnType("timestamp with time zone"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("SuspectId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id", "At"); + + b.HasIndex("SuspectId"); + + b.ToTable("TenantVersion", "gr"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany("Apps") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppRelationEntity", "App") + .WithMany() + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("App"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.App.AppSubjectRelationEntity", "AppSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppSubjectRelation"); + + b.Navigation("InternalAuthority"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AppSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "AppId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Security.AuthorityEntity", "InternalAuthority") + .WithMany() + .HasForeignKey("InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "TenantSubjectRelation") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InternalAuthority"); + + b.Navigation("TenantSubjectRelation"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Security.TenantSubjectRelationInternalAuthorityRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId", "InternalAuthorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SignIn.SignInEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany("SignInMethods") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantSubjectRelationEntity", "Reference") + .WithMany() + .HasForeignKey("SubjectId", "TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantVersionEntity", b => + { + b.HasOne("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", "Reference") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", "Suspect") + .WithMany() + .HasForeignKey("SuspectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reference"); + + b.Navigation("Suspect"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Subject.SubjectEntity", b => + { + b.Navigation("SignInMethods"); + }); + + modelBuilder.Entity("W542.GandalfReborn.Data.Entities.Tenant.TenantEntity", b => + { + b.Navigation("Apps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Docker/docker-compose.yml b/Docker/docker-compose.yml new file mode 100644 index 0000000..cbcc125 --- /dev/null +++ b/Docker/docker-compose.yml @@ -0,0 +1,13 @@ +services: + db: + image: postgres:16.4 + container_name: gandalf_reborn_db + restart: always + shm_size: 128mb + environment: + POSTGRES_PASSWORD: root + POSTGRES_USER: root + POSTGRES_DB: gandalf_reborn + ports: + - "5432:5432" + \ No newline at end of file diff --git a/Scripts/add-migration.cmd b/Scripts/add-migration.cmd new file mode 100644 index 0000000..4652f25 --- /dev/null +++ b/Scripts/add-migration.cmd @@ -0,0 +1,3 @@ +@echo off +set /p migrationName="Migration Name: " +dotnet ef migrations add %migrationName% --startup-project "../Api" --project "../Data" --context ApplicationContext \ No newline at end of file diff --git a/Scripts/reset-database.cmd b/Scripts/reset-database.cmd new file mode 100644 index 0000000..20bf518 --- /dev/null +++ b/Scripts/reset-database.cmd @@ -0,0 +1,3 @@ +@echo off +dotnet ef database drop --force --startup-project "../Api" --project "../Data" --context ApplicationContext +dotnet ef database update --startup-project "../Api" --project "../Data" --context ApplicationContext \ No newline at end of file diff --git a/Scripts/update-database.cmd b/Scripts/update-database.cmd new file mode 100644 index 0000000..2174d5f --- /dev/null +++ b/Scripts/update-database.cmd @@ -0,0 +1,2 @@ +@echo off +dotnet ef database update --startup-project "../Api" --project "../Data" --context ApplicationContext \ No newline at end of file diff --git a/Security/GrAuthorizeAttribute.cs b/Security/GrAuthorizeAttribute.cs new file mode 100644 index 0000000..2a93265 --- /dev/null +++ b/Security/GrAuthorizeAttribute.cs @@ -0,0 +1,62 @@ +using Abstractions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using W542.GandalfReborn.Data.Entities.Security; + +namespace Security; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] +public class GrAuthorizeAttribute : Attribute, IAuthorizationFilter +{ + public required string[] Authorities { get; init; } + public required AuthorityType Type { get; init; } + public required string ParameterName { get; init; } + public bool AllRequired { get; init; } = true; + + public void OnAuthorization(AuthorizationFilterContext context) + { + if(IsAnonymousAllowed(context)) return; + + var invoker = (Invoker)context.HttpContext.User; + + if (!invoker.IsAuthenticated) + { + HandleResponse(context, "One does not simply access this endpoint not authenticated.", StatusCodes.Status401Unauthorized); + return; + } + + var id = context.HttpContext.Request.RouteValues.GetValueOrDefault(ParameterName)?.ToString(); + + if (id is null) + { + HandleResponse(context, "One does not simply cause a internal server error.", StatusCodes.Status500InternalServerError); + return; + } + + var missingAuthorities = Type switch + { + AuthorityType.Tenant => Authorities.Where(x => !(invoker.TenantAuthorityDictionary.GetValueOrDefault(id)?.Contains(x) ?? false)).ToArray(), + AuthorityType.App => Authorities.Where(x => !(invoker.AppAuthorityDictionary.GetValueOrDefault(id)?.Contains(x) ?? false)).ToArray(), + _ => Authorities + }; + + if (missingAuthorities.Length == 0) return; + + var typeName = Type == AuthorityType.App ? "app" : "tenant"; + HandleResponse(context, $"One does not simply access this endpoint without {typeName} authorization.", StatusCodes.Status403Forbidden, missingAuthorities); + } + + private static void HandleResponse(AuthorizationFilterContext context, string message, int statusCode, string[]? missingAuthorities = null) + { + context.Result = missingAuthorities is null + ? new JsonResult(new { StatusCode = statusCode, Message = message }) { StatusCode = statusCode } + : new JsonResult(new { StatusCode = statusCode, Message = message, MissingAuthorities = missingAuthorities }) { StatusCode = statusCode }; + } + + private static bool IsAnonymousAllowed(AuthorizationFilterContext context) + { + return context.ActionDescriptor.EndpointMetadata.OfType().Any(); + } +} \ No newline at end of file diff --git a/Security/Scheme/GandalfRebornJwtTokenAuthExtensions.cs b/Security/Scheme/GandalfRebornJwtTokenAuthExtensions.cs new file mode 100644 index 0000000..eef1728 --- /dev/null +++ b/Security/Scheme/GandalfRebornJwtTokenAuthExtensions.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Security.Scheme; + +public static class GandalfRebornJwtTokenAuthExtensions +{ + private const string SchemeName = "GandalfRebornJwtTokenAuthScheme"; + + public static IServiceCollection AddGandalfRebornJwtTokenAuth(this IServiceCollection services, Action options) + { + services.AddAuthentication().AddScheme(SchemeName, options); + return services; + } +} \ No newline at end of file diff --git a/Security/Scheme/GandalfRebornJwtTokenAuthSchemeHandler.cs b/Security/Scheme/GandalfRebornJwtTokenAuthSchemeHandler.cs new file mode 100644 index 0000000..c52cf23 --- /dev/null +++ b/Security/Scheme/GandalfRebornJwtTokenAuthSchemeHandler.cs @@ -0,0 +1,157 @@ +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Text.RegularExpressions; +using Abstractions; +using HashidsNet; +using JWT.Algorithms; +using JWT.Builder; +using JWT.Serializers; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Routing; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using W542.GandalfReborn.Data.Database; + +namespace Security.Scheme; + +public class GandalfRebornJwtBody +{ + public string? Id { get; init; } + public string? Sub { get; init; } + public DateTimeOffset? Iat { get; init; } + public DateTimeOffset? Exp { get; init; } + public string? Iss { get; init; } + public string? Aud { get; init; } +} + +public partial class GandalfRebornJwtTokenAuthSchemeHandler( + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + IHashids hashIds, + ApplicationContext context, + IHttpContextAccessor httpContextAccessor, + InvokerContext invokerContext, + TimeProvider timeProvider) + : AuthenticationHandler(options, logger, encoder) +{ + [GeneratedRegex(@"Bearer\s+(?[A-Za-z0-9\-._~+\/]+=*\.[A-Za-z0-9\-._~+\/]+=*\.[A-Za-z0-9\-._~+\/]+=*)")] + private static partial Regex BearerTokenRegex(); + + private string FailReason { get; set; } = ""; + + protected override async Task HandleAuthenticateAsync() + { + try + { + var jwtBody = GetJwtTokenBody(httpContextAccessor.HttpContext); + + if (!hashIds.TryDecodeSingleLong(jwtBody.Sub, out var subjectId)) + { + throw new UnauthorizedAccessException("One does not simply authenticate with invalid id."); + } + + var subjectExists = context.Subjects.Any(x => x.Id == subjectId); + + if (!subjectExists) + { + throw new UnauthorizedAccessException("One does not simply authenticate with a not existing subject."); + } + + var claims = new List + { + new(Invoker.SubType, subjectId.ToString()) + }; + + var tenantAuthorities = await context.TenantSubjectRelations + .AsNoTracking() + .Where(x => x.SubjectId == subjectId) + .Include(x => x.InternalAuthorities) + .ToDictionaryAsync(x => x.TenantId, x => x.InternalAuthorities.Select(authority => authority.Name)); + + var appAuthorities = await context.AppSubjectRelations + .AsNoTracking() + .Where(x => x.SubjectId == subjectId) + .Include(x => x.InternalAuthorities) + .ToDictionaryAsync(x => x.AppId, x => x.InternalAuthorities.Select(authority => authority.Name)); + + var tenantClaims = tenantAuthorities + .SelectMany(x => x.Value.Select(authority => new Claim($"{Invoker.TenantAuthorityPrefix}{Invoker.AuthoritySeparator}{hashIds.EncodeLong(x.Key)}", authority))); + + var appClaims = appAuthorities + .SelectMany(x => x.Value.Select(authority => new Claim($"{Invoker.AppAuthorityPrefix}{Invoker.AuthoritySeparator}{hashIds.EncodeLong(x.Key)}", authority))); + + claims.AddRange(tenantClaims); + claims.AddRange(appClaims); + + var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Tokens")); + + invokerContext.Invoker = principal; + + var ticket = new AuthenticationTicket(principal, Scheme.Name); + return AuthenticateResult.Success(ticket); + } + catch (Exception ex) + { + FailReason = ex.Message; + return AuthenticateResult.Fail(ex); + } + } + + protected override async Task HandleChallengeAsync(AuthenticationProperties properties) + { + await base.HandleChallengeAsync(properties); + if (Response.StatusCode == StatusCodes.Status401Unauthorized && + !string.IsNullOrWhiteSpace(FailReason)) + { + Response.ContentType = "application/json"; + var executor = Context.RequestServices.GetRequiredService>(); + var actionContext = new ActionContext(Context, Context.GetRouteData(), new ActionDescriptor()); + await executor.ExecuteAsync(actionContext, new UnauthorizedObjectResult(new + { + status = Response.StatusCode, + error = FailReason, + })); + } + } + + private GandalfRebornJwtBody GetJwtTokenBody(HttpContext? httpContext) + { + var authHeader = httpContext?.Request.Headers.Authorization.ToString(); + + if (authHeader is null) + throw new UnauthorizedAccessException("One does not simply not provide an authorization header."); + + var tokenRegexMatch = BearerTokenRegex().Match(authHeader); + + if (!tokenRegexMatch.Success) + throw new UnauthorizedAccessException("One does not simply provide an invalid authorization header."); + + var token = tokenRegexMatch.Groups["token"].Value; + + var decodedToken = JwtBuilder.Create() + .WithAlgorithm(new HMACSHA512Algorithm()) + .WithSecret(Options.JwtSecret) + .MustVerifySignature() + .WithJsonSerializer(new JsonNetSerializer()) + .Decode(token); + + if (decodedToken.Aud is null || !decodedToken.Aud.StartsWith(Options.BaseUrl)) + throw new UnauthorizedAccessException("One does not simply provide a token for a different audience."); + + if (decodedToken.Iss is null || !decodedToken.Iss.StartsWith(Options.BaseUrl)) + throw new UnauthorizedAccessException("One does not simply provide a token from a unknown issuer."); + + if (decodedToken.Exp is null || decodedToken.Exp?.ToUniversalTime() <= timeProvider.GetUtcNow()) + throw new UnauthorizedAccessException("One does not simply provide an expired token."); + + return decodedToken; + } +} \ No newline at end of file diff --git a/Security/Scheme/GandalfRebornJwtTokenAuthSchemeOptions.cs b/Security/Scheme/GandalfRebornJwtTokenAuthSchemeOptions.cs new file mode 100644 index 0000000..1830b38 --- /dev/null +++ b/Security/Scheme/GandalfRebornJwtTokenAuthSchemeOptions.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Authentication; + +namespace Security.Scheme; + +public class GandalfRebornJwtTokenAuthSchemeOptions : AuthenticationSchemeOptions +{ + public string JwtSecret { get; set; } = "superSecret"; + public string BaseUrl { get; set; } = ""; +} \ No newline at end of file diff --git a/Security/Security.csproj b/Security/Security.csproj new file mode 100644 index 0000000..a2b46fe --- /dev/null +++ b/Security/Security.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + diff --git a/Service/Service.csproj b/Service/Service.csproj new file mode 100644 index 0000000..4221add --- /dev/null +++ b/Service/Service.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/W542.GandalfReborn.sln b/W542.GandalfReborn.sln new file mode 100644 index 0000000..205a2d2 --- /dev/null +++ b/W542.GandalfReborn.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Api", "Api\Api.csproj", "{067494CB-FE63-42F0-A154-586E50442969}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{B4AF6985-3268-4C2E-9C50-D92DA7D3711D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Security", "Security\Security.csproj", "{C8C3047B-ED0B-4516-A282-8B07E3EEB430}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abstractions", "Abstractions\Abstractions.csproj", "{44C283FD-2E01-496C-9E8F-4E43C26C9733}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {067494CB-FE63-42F0-A154-586E50442969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {067494CB-FE63-42F0-A154-586E50442969}.Debug|Any CPU.Build.0 = Debug|Any CPU + {067494CB-FE63-42F0-A154-586E50442969}.Release|Any CPU.ActiveCfg = Release|Any CPU + {067494CB-FE63-42F0-A154-586E50442969}.Release|Any CPU.Build.0 = Release|Any CPU + {B4AF6985-3268-4C2E-9C50-D92DA7D3711D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4AF6985-3268-4C2E-9C50-D92DA7D3711D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4AF6985-3268-4C2E-9C50-D92DA7D3711D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4AF6985-3268-4C2E-9C50-D92DA7D3711D}.Release|Any CPU.Build.0 = Release|Any CPU + {C8C3047B-ED0B-4516-A282-8B07E3EEB430}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C8C3047B-ED0B-4516-A282-8B07E3EEB430}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8C3047B-ED0B-4516-A282-8B07E3EEB430}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C8C3047B-ED0B-4516-A282-8B07E3EEB430}.Release|Any CPU.Build.0 = Release|Any CPU + {44C283FD-2E01-496C-9E8F-4E43C26C9733}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44C283FD-2E01-496C-9E8F-4E43C26C9733}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44C283FD-2E01-496C-9E8F-4E43C26C9733}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44C283FD-2E01-496C-9E8F-4E43C26C9733}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal