| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  | using System.Security.Cryptography; | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  | using Foxchat.Core; | 
					
						
							|  |  |  | using Foxchat.Identity.Utils; | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  | using Microsoft.AspNetCore.WebUtilities; | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  | using Microsoft.EntityFrameworkCore; | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Foxchat.Identity.Database.Models; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public class Application : BaseModel | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     public required string ClientId { get; init; } | 
					
						
							|  |  |  |     public required string ClientSecret { get; init; } | 
					
						
							|  |  |  |     public required string Name { get; init; } | 
					
						
							|  |  |  |     public required string[] Scopes { get; init; } | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  |     public required string[] RedirectUris { get; set; } | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  |     public static Application Create(string name, string[] scopes, string[] redirectUrls) | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  |         var clientId = RandomNumberGenerator.GetHexString(32, true); | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  |         var clientSecretBytes = RandomNumberGenerator.GetBytes(48); | 
					
						
							|  |  |  |         var clientSecret = WebEncoders.Base64UrlEncode(clientSecretBytes); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  |         if (scopes.Any(s => !OauthUtils.Scopes.Contains(s))) | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             throw new ArgumentException("Invalid scopes passed to Application.Create", nameof(scopes)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  |         if (redirectUrls.Any(s => !OauthUtils.ValidateRedirectUri(s))) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             throw new ArgumentException("Invalid redirect URLs passed to Application.Create", nameof(redirectUrls)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  |         return new Application | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             ClientId = clientId, | 
					
						
							|  |  |  |             ClientSecret = clientSecret, | 
					
						
							|  |  |  |             Name = name, | 
					
						
							|  |  |  |             Scopes = scopes, | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  |             RedirectUris = redirectUrls | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  |         }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  | public static class ContextApplicationExtensions | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-05-20 17:00:21 +02:00
										 |  |  |     public static async Task<Application> GetApplicationAsync(this IdentityContext db, string clientId) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return await db.Applications.FirstOrDefaultAsync(a => a.ClientId == clientId) | 
					
						
							|  |  |  |             ?? throw new ApiError.Unauthorized("Invalid client ID or client secret"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static async Task<Application> GetApplicationAsync(this IdentityContext db, string clientId, string clientSecret) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         var app = await db.GetApplicationAsync(clientId); | 
					
						
							|  |  |  |         if (app.ClientSecret != clientSecret) throw new ApiError.Unauthorized("Invalid client ID or client secret"); | 
					
						
							|  |  |  |         return app; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-05-19 17:20:45 +02:00
										 |  |  | } |