chat: add initial GuildsController
This commit is contained in:
		
							parent
							
								
									7b4cbd4fb7
								
							
						
					
					
						commit
						727f2f6ba2
					
				
					 23 changed files with 248 additions and 38 deletions
				
			
		|  | @ -2,3 +2,6 @@ | |||
| 
 | ||||
| # CS9113: Parameter is unread. | ||||
| dotnet_diagnostic.CS9113.severity = silent | ||||
| 
 | ||||
| # EntityFramework.ModelValidation.UnlimitedStringLength | ||||
| resharper_entity_framework_model_validation_unlimited_string_length_highlighting=none | ||||
							
								
								
									
										44
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,3 +1,47 @@ | |||
| bin/ | ||||
| obj/ | ||||
| .version | ||||
| 
 | ||||
| # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider | ||||
| # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | ||||
| 
 | ||||
| # User-specific stuff | ||||
| .idea/**/workspace.xml | ||||
| .idea/**/tasks.xml | ||||
| .idea/**/usage.statistics.xml | ||||
| .idea/**/dictionaries | ||||
| .idea/**/shelf | ||||
| .idea/**/discord.xml | ||||
| 
 | ||||
| # Generated files | ||||
| .idea/**/contentModel.xml | ||||
| 
 | ||||
| # Sensitive or high-churn files | ||||
| .idea/**/dataSources/ | ||||
| .idea/**/dataSources.ids | ||||
| .idea/**/dataSources.local.xml | ||||
| .idea/**/sqlDataSources.xml | ||||
| .idea/**/dynamic.xml | ||||
| .idea/**/uiDesigner.xml | ||||
| .idea/**/dbnavigator.xml | ||||
| 
 | ||||
| # Gradle | ||||
| .idea/**/gradle.xml | ||||
| .idea/**/libraries | ||||
| 
 | ||||
| # CMake | ||||
| cmake-build-*/ | ||||
| 
 | ||||
| # File-based project format | ||||
| *.iws | ||||
| 
 | ||||
| # Editor-based Rest Client | ||||
| .idea/httpRequests | ||||
| 
 | ||||
| # Visual Studio Code | ||||
| .vscode/* | ||||
| !.vscode/settings.json | ||||
| !.vscode/tasks.json | ||||
| !.vscode/launch.json | ||||
| !.vscode/extensions.json | ||||
| !.vscode/*.code-snippets | ||||
|  |  | |||
							
								
								
									
										47
									
								
								Foxchat.Chat/Controllers/Api/GuildsController.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Foxchat.Chat/Controllers/Api/GuildsController.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| using Foxchat.Chat.Database; | ||||
| using Foxchat.Chat.Database.Models; | ||||
| using Foxchat.Chat.Middleware; | ||||
| using Foxchat.Chat.Services; | ||||
| using Foxchat.Core.Models; | ||||
| using Foxchat.Core.Models.Http; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using ApiError = Foxchat.Core.ApiError; | ||||
| 
 | ||||
| namespace Foxchat.Chat.Controllers.Api; | ||||
| 
 | ||||
| [ApiController] | ||||
| [Route("/_fox/chat/guilds")] | ||||
| public class GuildsController(ILogger logger, ChatContext db, UserResolverService userResolverService) : ControllerBase | ||||
| { | ||||
|     [HttpPost] | ||||
|     public async Task<IActionResult> CreateGuild([FromBody] GuildsApi.CreateGuildRequest req) | ||||
|     { | ||||
|         var (instance, sig) = HttpContext.GetSignatureOrThrow(); | ||||
|         if (sig.UserId == null) throw new ApiError.IncomingFederationError("This endpoint requires a user ID."); | ||||
| 
 | ||||
|         var user = await userResolverService.ResolveUserAsync(instance, sig.UserId); | ||||
| 
 | ||||
|         var guild = new Guild | ||||
|         { | ||||
|             Name = req.Name, | ||||
|             Owner = user, | ||||
|         }; | ||||
|         db.Add(guild); | ||||
|         guild.Users.Add(user); | ||||
|         var defaultChannel = new Channel | ||||
|         { | ||||
|             Guild = guild, | ||||
|             Name = "general" | ||||
|         }; | ||||
|         db.Add(defaultChannel); | ||||
| 
 | ||||
|         await db.SaveChangesAsync(); | ||||
| 
 | ||||
|         return Ok(new Guilds.Guild( | ||||
|             guild.Id.ToString(),  | ||||
|             guild.Name,  | ||||
|             [user.Id.ToString()], | ||||
|             [new Channels.PartialChannel(defaultChannel.Id.ToString(), defaultChannel.Name)]) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | @ -10,7 +10,7 @@ using ApiError = Foxchat.Core.ApiError; | |||
| namespace Foxchat.Chat.Controllers; | ||||
| 
 | ||||
| [ApiController] | ||||
| [Unauthenticated] | ||||
| [ServerUnauthenticated] | ||||
| [Route("/_fox/chat/hello")] | ||||
| public class HelloController( | ||||
|     ILogger logger, | ||||
|  | @ -27,6 +27,8 @@ public class HelloController( | |||
| 
 | ||||
|         if (!HttpContext.ExtractRequestData(out var signature, out var domain, out var signatureData)) | ||||
|             throw new ApiError.IncomingFederationError("This endpoint requires signed requests."); | ||||
|         if (domain != req.Host) | ||||
|             throw new ApiError.IncomingFederationError("Host is invalid."); | ||||
| 
 | ||||
|         if (!requestSigningService.VerifySignature(node.PublicKey, signature, signatureData)) | ||||
|             throw new ApiError.IncomingFederationError("Signature is not valid."); | ||||
|  |  | |||
|  | @ -1,3 +1,6 @@ | |||
| using Foxchat.Core.Models; | ||||
| using NodaTime; | ||||
| 
 | ||||
| namespace Foxchat.Chat.Database.Models; | ||||
| 
 | ||||
| public class User : BaseModel | ||||
|  | @ -8,6 +11,7 @@ public class User : BaseModel | |||
|     public string Username { get; init; } = null!; | ||||
| 
 | ||||
|     public string? Avatar { get; set; } | ||||
|     public Instant LastFetchedAt { get; set; } | ||||
| 
 | ||||
|     public List<Guild> Guilds { get; } = []; | ||||
|     public List<Guild> OwnedGuilds { get; } = []; | ||||
|  |  | |||
|  | @ -1,4 +1,6 @@ | |||
| using Foxchat.Chat.Middleware; | ||||
| using Foxchat.Chat.Services; | ||||
| using Foxchat.Core.Middleware; | ||||
| 
 | ||||
| namespace Foxchat.Chat.Extensions; | ||||
| 
 | ||||
|  | @ -7,12 +9,20 @@ public static class WebApplicationExtensions | |||
|     public static IServiceCollection AddCustomMiddleware(this IServiceCollection services) | ||||
|     { | ||||
|         return services | ||||
|             .AddScoped<AuthenticationMiddleware>(); | ||||
|             .AddScoped<ErrorHandlerMiddleware>() | ||||
|             .AddScoped<ServerAuthenticationMiddleware>(); | ||||
|     } | ||||
| 
 | ||||
|     public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder app) | ||||
|     { | ||||
|         return app | ||||
|             .UseMiddleware<AuthenticationMiddleware>(); | ||||
|             .UseMiddleware<ErrorHandlerMiddleware>() | ||||
|             .UseMiddleware<ServerAuthenticationMiddleware>(); | ||||
|     } | ||||
| 
 | ||||
|     public static IServiceCollection AddChatServices(this IServiceCollection services) | ||||
|     { | ||||
|         return services | ||||
|             .AddScoped<UserResolverService>(); | ||||
|     } | ||||
| } | ||||
|  | @ -7,14 +7,14 @@ using Microsoft.EntityFrameworkCore; | |||
| 
 | ||||
| namespace Foxchat.Chat.Middleware; | ||||
| 
 | ||||
| public class AuthenticationMiddleware(ILogger logger, ChatContext db, RequestSigningService requestSigningService) | ||||
| public class ServerAuthenticationMiddleware(ILogger logger, ChatContext db, RequestSigningService requestSigningService) | ||||
|     : IMiddleware | ||||
| { | ||||
|     public async Task InvokeAsync(HttpContext ctx, RequestDelegate next) | ||||
|     { | ||||
|         var endpoint = ctx.GetEndpoint(); | ||||
|         // Endpoints require server authentication by default, unless they have the [Unauthenticated] attribute. | ||||
|         var metadata = endpoint?.Metadata.GetMetadata<UnauthenticatedAttribute>(); | ||||
|         var metadata = endpoint?.Metadata.GetMetadata<ServerUnauthenticatedAttribute>(); | ||||
|         if (metadata != null) | ||||
|         { | ||||
|             await next(ctx); | ||||
|  | @ -41,8 +41,11 @@ public class AuthenticationMiddleware(ILogger logger, ChatContext db, RequestSig | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Attribute to be put on controllers or methods to indicate that it does <i>not</i> require a signed request. | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | ||||
| public class UnauthenticatedAttribute : Attribute; | ||||
| public class ServerUnauthenticatedAttribute : Attribute; | ||||
| 
 | ||||
| public static class HttpContextExtensions | ||||
| { | ||||
|  | @ -34,6 +34,7 @@ builder.Services | |||
| 
 | ||||
| builder.Services | ||||
|     .AddCoreServices<ChatContext>() | ||||
|     .AddChatServices() | ||||
|     .AddCustomMiddleware() | ||||
|     .AddEndpointsApiExplorer() | ||||
|     .AddSwaggerGen(); | ||||
|  |  | |||
							
								
								
									
										35
									
								
								Foxchat.Chat/Services/UserResolverService.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Foxchat.Chat/Services/UserResolverService.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | |||
| using Foxchat.Chat.Database; | ||||
| using Foxchat.Chat.Database.Models; | ||||
| using Foxchat.Core.Federation; | ||||
| using Foxchat.Core.Models; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| 
 | ||||
| namespace Foxchat.Chat.Services; | ||||
| 
 | ||||
| public class UserResolverService(ILogger logger, ChatContext db, RequestSigningService requestSigningService) | ||||
| { | ||||
|     public async Task<User> ResolveUserAsync(IdentityInstance instance, string userId) | ||||
|     { | ||||
|         var user = await db.Users.FirstOrDefaultAsync(u => u.InstanceId == instance.Id && u.RemoteUserId == userId); | ||||
|         if (user != null) | ||||
|         { | ||||
|             // TODO: update user if it's been long enough | ||||
|             return user; | ||||
|         } | ||||
| 
 | ||||
|         var userResponse = await requestSigningService.RequestAsync<Users.User>(HttpMethod.Get, instance.Domain, | ||||
|             $"/_fox/ident/users/{userId}"); | ||||
| 
 | ||||
|         user = new User | ||||
|         { | ||||
|             Instance = instance, | ||||
|             Username = userResponse.Username, | ||||
|             RemoteUserId = userResponse.Id, | ||||
|             Avatar = userResponse.AvatarUrl | ||||
|         }; | ||||
| 
 | ||||
|         db.Add(user); | ||||
|         await db.SaveChangesAsync(); | ||||
|         return user; | ||||
|     } | ||||
| } | ||||
|  | @ -1,3 +1,4 @@ | |||
| using System.Diagnostics.CodeAnalysis; | ||||
| using Foxchat.Core.Federation; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| 
 | ||||
|  | @ -5,11 +6,12 @@ namespace Foxchat.Core.Extensions; | |||
| 
 | ||||
| public static class HttpContextExtensions | ||||
| { | ||||
|     public static bool ExtractRequestData(this HttpContext ctx, out string signature, out string domain, out SignatureData data) | ||||
|     public static bool ExtractRequestData(this HttpContext ctx, [NotNullWhen(true)] out string? signature, | ||||
|         [NotNullWhen(true)] out string? domain, [NotNullWhen(true)] out SignatureData? data) | ||||
|     { | ||||
|         signature = string.Empty; | ||||
|         domain = string.Empty; | ||||
|         data = SignatureData.Empty; | ||||
|         signature = null; | ||||
|         domain = null; | ||||
|         data = null; | ||||
| 
 | ||||
|         if (!ctx.Request.Headers.TryGetValue(RequestSigningService.SIGNATURE_HEADER, out var encodedSignature)) | ||||
|             return false; | ||||
|  |  | |||
|  | @ -33,18 +33,17 @@ public partial class RequestSigningService(ILogger logger, IClock clock, IDataba | |||
|     public bool VerifySignature( | ||||
|         string publicKey, string encodedSignature, SignatureData data) | ||||
|     { | ||||
|         var rsa = RSA.Create(); | ||||
|         rsa.ImportFromPem(publicKey); | ||||
|         if (data.Host != _config.Domain) | ||||
|             throw new ApiError.IncomingFederationError("Request is not for this instance"); | ||||
| 
 | ||||
|         var now = _clock.GetCurrentInstant(); | ||||
|         if ((now + Duration.FromMinutes(1)) < data.Time) | ||||
|         { | ||||
|         if (now + Duration.FromMinutes(1) < data.Time) | ||||
|             throw new ApiError.IncomingFederationError("Request was made in the future"); | ||||
|         } | ||||
|         else if ((now - Duration.FromMinutes(1)) > data.Time) | ||||
|         { | ||||
|         if (now - Duration.FromMinutes(1) > data.Time) | ||||
|             throw new ApiError.IncomingFederationError("Request was made too long ago"); | ||||
|         } | ||||
| 
 | ||||
|         var rsa = RSA.Create(); | ||||
|         rsa.ImportFromPem(publicKey); | ||||
| 
 | ||||
|         var plaintext = GeneratePlaintext(data); | ||||
|         var plaintextBytes = Encoding.UTF8.GetBytes(plaintext); | ||||
|  | @ -70,7 +69,9 @@ public partial class RequestSigningService(ILogger logger, IClock clock, IDataba | |||
|         return $"{time}:{data.Host}:{data.RequestPath}:{contentLength}:{userId}"; | ||||
|     } | ||||
| 
 | ||||
|     private static readonly InstantPattern _pattern = InstantPattern.Create("ddd, dd MMM yyyy HH:mm:ss 'GMT'", CultureInfo.GetCultureInfo("en-US")); | ||||
|     private static readonly InstantPattern _pattern = | ||||
|         InstantPattern.Create("ddd, dd MMM yyyy HH:mm:ss 'GMT'", CultureInfo.GetCultureInfo("en-US")); | ||||
| 
 | ||||
|     private static string FormatTime(Instant time) => _pattern.Format(time); | ||||
|     public static Instant ParseTime(string header) => _pattern.Parse(header).GetValueOrThrow(); | ||||
| } | ||||
| } | ||||
|  | @ -1,11 +1,10 @@ | |||
| using System.Net; | ||||
| using Foxchat.Core; | ||||
| using Foxchat.Core.Models.Http; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Newtonsoft.Json; | ||||
| using ApiError = Foxchat.Core.ApiError; | ||||
| using HttpApiError = Foxchat.Core.Models.Http.ApiError; | ||||
| 
 | ||||
| namespace Foxchat.Identity.Middleware; | ||||
| namespace Foxchat.Core.Middleware; | ||||
| 
 | ||||
| public class ErrorHandlerMiddleware(ILogger baseLogger) : IMiddleware | ||||
| { | ||||
|  | @ -23,7 +22,8 @@ public class ErrorHandlerMiddleware(ILogger baseLogger) : IMiddleware | |||
| 
 | ||||
|             if (ctx.Response.HasStarted) | ||||
|             { | ||||
|                 logger.Error(e, "Error in {ClassName} ({Path}) after response started being sent", typeName, ctx.Request.Path); | ||||
|                 logger.Error(e, "Error in {ClassName} ({Path}) after response started being sent", typeName, | ||||
|                     ctx.Request.Path); | ||||
|             } | ||||
| 
 | ||||
|             if (e is ApiError ae) | ||||
							
								
								
									
										8
									
								
								Foxchat.Core/Models/Channels.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Foxchat.Core/Models/Channels.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| namespace Foxchat.Core.Models; | ||||
| 
 | ||||
| public static class Channels | ||||
| { | ||||
|     public record Channel(string Id, string GuildId, string Name, string? Topic); | ||||
| 
 | ||||
|     public record PartialChannel(string Id, string Name); | ||||
| } | ||||
							
								
								
									
										14
									
								
								Foxchat.Core/Models/Guilds.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Foxchat.Core/Models/Guilds.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| using Newtonsoft.Json; | ||||
| 
 | ||||
| namespace Foxchat.Core.Models; | ||||
| 
 | ||||
| public static class Guilds | ||||
| { | ||||
|     public record Guild( | ||||
|         string Id, | ||||
|         string Name, | ||||
|         IEnumerable<string> OwnerIds, | ||||
|         [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|         IEnumerable<Channels.PartialChannel>? Channels | ||||
|     ); | ||||
| } | ||||
|  | @ -1,6 +1,6 @@ | |||
| namespace Foxchat.Core.Models.Http; | ||||
| 
 | ||||
| public static class Apps | ||||
| public static class AppsApi | ||||
| { | ||||
|     public record CreateRequest(string Name, string[] Scopes, string[] RedirectUris); | ||||
|     public record CreateResponse(Ulid Id, string ClientId, string ClientSecret, string Name, string[] Scopes, string[] RedirectUris); | ||||
							
								
								
									
										6
									
								
								Foxchat.Core/Models/Http/GuildsApi.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Foxchat.Core/Models/Http/GuildsApi.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| namespace Foxchat.Core.Models.Http; | ||||
| 
 | ||||
| public static class GuildsApi | ||||
| { | ||||
|     public record CreateGuildRequest(string Name); | ||||
| } | ||||
							
								
								
									
										8
									
								
								Foxchat.Core/Models/Users.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Foxchat.Core/Models/Users.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| namespace Foxchat.Core.Models; | ||||
| 
 | ||||
| public static class Users | ||||
| { | ||||
|     public record User(string Id, string Username, string Instance, string? AvatarUrl); | ||||
| 
 | ||||
|     public record PartialUser(string Id, string Username, string Instance); | ||||
| } | ||||
|  | @ -9,12 +9,12 @@ using Microsoft.AspNetCore.Mvc; | |||
| namespace Foxchat.Identity.Controllers.Oauth; | ||||
| 
 | ||||
| [ApiController] | ||||
| [Authenticate] | ||||
| [ClientAuthenticate] | ||||
| [Route("/_fox/ident/oauth/apps")] | ||||
| public class AppsController(ILogger logger, IdentityContext db) : ControllerBase | ||||
| { | ||||
|     [HttpPost] | ||||
|     public async Task<IActionResult> CreateApplication([FromBody] Apps.CreateRequest req) | ||||
|     public async Task<IActionResult> CreateApplication([FromBody] AppsApi.CreateRequest req) | ||||
|     { | ||||
|         var app = Application.Create(req.Name, req.Scopes, req.RedirectUris); | ||||
|         db.Add(app); | ||||
|  | @ -22,7 +22,7 @@ public class AppsController(ILogger logger, IdentityContext db) : ControllerBase | |||
| 
 | ||||
|         logger.Information("Created new application {Name} with ID {Id} and client ID {ClientId}", app.Name, app.Id, app.ClientId); | ||||
| 
 | ||||
|         return Ok(new Apps.CreateResponse( | ||||
|         return Ok(new AppsApi.CreateResponse( | ||||
|             app.Id, app.ClientId, app.ClientSecret, app.Name, app.Scopes, app.RedirectUris | ||||
|         )); | ||||
|     } | ||||
|  | @ -32,7 +32,7 @@ public class AppsController(ILogger logger, IdentityContext db) : ControllerBase | |||
|     { | ||||
|         var app = HttpContext.GetApplicationOrThrow(); | ||||
| 
 | ||||
|         return Ok(new Apps.GetSelfResponse( | ||||
|         return Ok(new AppsApi.GetSelfResponse( | ||||
|             app.Id, | ||||
|             app.ClientId, | ||||
|             withSecret ? app.ClientSecret : null, | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ using Microsoft.EntityFrameworkCore; | |||
| namespace Foxchat.Identity.Controllers.Oauth; | ||||
| 
 | ||||
| [ApiController] | ||||
| [Authenticate] | ||||
| [ClientAuthenticate] | ||||
| [Route("/_fox/ident/oauth/password")] | ||||
| public class PasswordAuthController(ILogger logger, IdentityContext db, IClock clock) : ControllerBase | ||||
| { | ||||
|  |  | |||
							
								
								
									
										21
									
								
								Foxchat.Identity/Controllers/UsersController.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								Foxchat.Identity/Controllers/UsersController.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| using Foxchat.Core; | ||||
| using Foxchat.Core.Models; | ||||
| using Foxchat.Identity.Database; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| 
 | ||||
| namespace Foxchat.Identity.Controllers; | ||||
| 
 | ||||
| [ApiController] | ||||
| [Route("/_fox/ident/users")] | ||||
| public class UsersController(ILogger logger, InstanceConfig config, IdentityContext db) : ControllerBase | ||||
| { | ||||
|     [HttpGet("{id}")] | ||||
|     public async Task<IActionResult> GetUser(Ulid id) | ||||
|     { | ||||
|         var user = await db.Accounts.FirstOrDefaultAsync(a => a.Id == id); | ||||
|         if (user == null) throw new ApiError.NotFound("User not found."); | ||||
| 
 | ||||
|         return Ok(new Users.User(user.Id.ToString(), user.Username, config.Domain, null)); | ||||
|     } | ||||
| } | ||||
|  | @ -1,3 +1,4 @@ | |||
| using Foxchat.Core.Middleware; | ||||
| using Foxchat.Identity.Middleware; | ||||
| 
 | ||||
| namespace Foxchat.Identity.Extensions; | ||||
|  | @ -8,15 +9,15 @@ public static class WebApplicationExtensions | |||
|     { | ||||
|         return services | ||||
|             .AddScoped<ErrorHandlerMiddleware>() | ||||
|             .AddScoped<AuthenticationMiddleware>() | ||||
|             .AddScoped<AuthorizationMiddleware>(); | ||||
|             .AddScoped<ClientAuthenticationMiddleware>() | ||||
|             .AddScoped<ClientAuthorizationMiddleware>(); | ||||
|     } | ||||
| 
 | ||||
|     public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder app) | ||||
|     { | ||||
|         return app | ||||
|             .UseMiddleware<ErrorHandlerMiddleware>() | ||||
|             .UseMiddleware<AuthenticationMiddleware>() | ||||
|             .UseMiddleware<AuthorizationMiddleware>(); | ||||
|             .UseMiddleware<ClientAuthenticationMiddleware>() | ||||
|             .UseMiddleware<ClientAuthorizationMiddleware>(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ using NodaTime; | |||
| 
 | ||||
| namespace Foxchat.Identity.Middleware; | ||||
| 
 | ||||
| public class AuthenticationMiddleware( | ||||
| public class ClientAuthenticationMiddleware( | ||||
|     IdentityContext db, | ||||
|     IClock clock | ||||
| ) : IMiddleware | ||||
|  | @ -16,7 +16,7 @@ public class AuthenticationMiddleware( | |||
|     public async Task InvokeAsync(HttpContext ctx, RequestDelegate next) | ||||
|     { | ||||
|         var endpoint = ctx.GetEndpoint(); | ||||
|         var metadata = endpoint?.Metadata.GetMetadata<AuthenticateAttribute>(); | ||||
|         var metadata = endpoint?.Metadata.GetMetadata<ClientAuthenticateAttribute>(); | ||||
| 
 | ||||
|         if (metadata == null) | ||||
|         { | ||||
|  | @ -81,4 +81,4 @@ public static class HttpContextExtensions | |||
| } | ||||
| 
 | ||||
| [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | ||||
| public class AuthenticateAttribute : Attribute; | ||||
| public class ClientAuthenticateAttribute : Attribute; | ||||
|  | @ -4,7 +4,7 @@ using NodaTime; | |||
| 
 | ||||
| namespace Foxchat.Identity.Middleware; | ||||
| 
 | ||||
| public class AuthorizationMiddleware( | ||||
| public class ClientAuthorizationMiddleware( | ||||
|     IdentityContext db, | ||||
|     IClock clock | ||||
| ) : IMiddleware | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue