add a bunch of authentication stuff
This commit is contained in:
		
							parent
							
								
									996e59f49a
								
							
						
					
					
						commit
						aca83fa1ef
					
				
					 22 changed files with 681 additions and 28 deletions
				
			
		
							
								
								
									
										6
									
								
								Foxchat.Identity/Database/BaseModel.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Foxchat.Identity/Database/BaseModel.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
namespace Foxchat.Identity.Database;
 | 
			
		||||
 | 
			
		||||
public abstract class BaseModel
 | 
			
		||||
{
 | 
			
		||||
    public Ulid Id { get; init; } = Ulid.NewUlid();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3,31 +3,37 @@ using Foxchat.Core.Database;
 | 
			
		|||
using Foxchat.Identity.Database.Models;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using Microsoft.EntityFrameworkCore.Design;
 | 
			
		||||
using Npgsql;
 | 
			
		||||
 | 
			
		||||
namespace Foxchat.Identity.Database;
 | 
			
		||||
 | 
			
		||||
public class IdentityContext : IDatabaseContext
 | 
			
		||||
{
 | 
			
		||||
    private readonly string _connString;
 | 
			
		||||
    private readonly NpgsqlDataSource _dataSource;
 | 
			
		||||
 | 
			
		||||
    public DbSet<Account> Accounts { get; set; }
 | 
			
		||||
    public DbSet<ChatInstance> ChatInstances { get; set; }
 | 
			
		||||
    public override DbSet<Instance> Instance { get; set; }
 | 
			
		||||
    public DbSet<Application> Applications { get; set; }
 | 
			
		||||
    public DbSet<Token> Tokens { get; set; }
 | 
			
		||||
    public DbSet<GuildAccount> GuildAccounts { get; set; }
 | 
			
		||||
 | 
			
		||||
    public IdentityContext(InstanceConfig config)
 | 
			
		||||
    {
 | 
			
		||||
        _connString = new Npgsql.NpgsqlConnectionStringBuilder(config.Database.Url)
 | 
			
		||||
        var connString = new NpgsqlConnectionStringBuilder(config.Database.Url)
 | 
			
		||||
        {
 | 
			
		||||
            Timeout = config.Database.Timeout ?? 5,
 | 
			
		||||
            MaxPoolSize = config.Database.MaxPoolSize ?? 50,
 | 
			
		||||
        }.ConnectionString;
 | 
			
		||||
 | 
			
		||||
        var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString);
 | 
			
		||||
        dataSourceBuilder.UseNodaTime();
 | 
			
		||||
        _dataSource = dataSourceBuilder.Build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 | 
			
		||||
            => optionsBuilder
 | 
			
		||||
                .UseNpgsql(_connString)
 | 
			
		||||
                .UseNpgsql(_dataSource, o => o.UseNodaTime())
 | 
			
		||||
                .UseSnakeCaseNamingConvention();
 | 
			
		||||
 | 
			
		||||
    protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +50,8 @@ public class IdentityContext : IDatabaseContext
 | 
			
		|||
        modelBuilder.Entity<ChatInstance>().HasIndex(i => i.Domain).IsUnique();
 | 
			
		||||
 | 
			
		||||
        modelBuilder.Entity<GuildAccount>().HasKey(g => new { g.ChatInstanceId, g.GuildId, g.AccountId });
 | 
			
		||||
 | 
			
		||||
        modelBuilder.Entity<Application>().HasIndex(a => a.ClientId).IsUnique();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,7 @@
 | 
			
		|||
namespace Foxchat.Identity.Database.Models;
 | 
			
		||||
 | 
			
		||||
public class Account
 | 
			
		||||
public class Account : BaseModel
 | 
			
		||||
{
 | 
			
		||||
    public Ulid Id { get; init; } = Ulid.NewUlid();
 | 
			
		||||
    public string Username { get; set; } = null!;
 | 
			
		||||
    public string Email { get; set; } = null!;
 | 
			
		||||
    public string Password { get; set; } = null!;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										46
									
								
								Foxchat.Identity/Database/Models/Application.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								Foxchat.Identity/Database/Models/Application.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
using System.Security.Cryptography;
 | 
			
		||||
using Microsoft.AspNetCore.WebUtilities;
 | 
			
		||||
 | 
			
		||||
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; }
 | 
			
		||||
 | 
			
		||||
    public static Application Create(string name, string[] scopes)
 | 
			
		||||
    {
 | 
			
		||||
        var clientId = RandomNumberGenerator.GetHexString(16, true);
 | 
			
		||||
        var clientSecretBytes = RandomNumberGenerator.GetBytes(48);
 | 
			
		||||
        var clientSecret = WebEncoders.Base64UrlEncode(clientSecretBytes);
 | 
			
		||||
 | 
			
		||||
        if (!scopes.All(s => Scope.ValidScopes.Contains(s)))
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentException("Invalid scopes passed to Application.Create", nameof(scopes));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new Application
 | 
			
		||||
        {
 | 
			
		||||
            ClientId = clientId,
 | 
			
		||||
            ClientSecret = clientSecret,
 | 
			
		||||
            Name = name,
 | 
			
		||||
            Scopes = scopes,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public static class Scope
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// OAuth scope for identifying a user and nothing else.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const string Identity = "identity";
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// OAuth scope for a full chat client. This grants *full access* to an account.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const string ChatClient = "chat_client";
 | 
			
		||||
 | 
			
		||||
    public static readonly string[] ValidScopes = [Identity, ChatClient];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +1,7 @@
 | 
			
		|||
namespace Foxchat.Identity.Database.Models;
 | 
			
		||||
 | 
			
		||||
public class ChatInstance
 | 
			
		||||
public class ChatInstance : BaseModel
 | 
			
		||||
{
 | 
			
		||||
    public Ulid Id { get; init; } = Ulid.NewUlid();
 | 
			
		||||
    public string Domain { get; init; } = null!;
 | 
			
		||||
    public string BaseUrl { get; set; } = null!;
 | 
			
		||||
    public string PublicKey { get; set; } = null!;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,26 @@
 | 
			
		|||
using System.Security.Cryptography;
 | 
			
		||||
using Foxchat.Core.Utils;
 | 
			
		||||
using NodaTime;
 | 
			
		||||
 | 
			
		||||
namespace Foxchat.Identity.Database.Models;
 | 
			
		||||
 | 
			
		||||
public class Token
 | 
			
		||||
public class Token : BaseModel
 | 
			
		||||
{
 | 
			
		||||
    public Ulid Id { get; init; } = Ulid.NewUlid();
 | 
			
		||||
    public byte[] Hash { get; set; } = null!;
 | 
			
		||||
    public string[] Scopes { get; set; } = [];
 | 
			
		||||
    public Instant Expires { get; set; }
 | 
			
		||||
 | 
			
		||||
    public Ulid AccountId { get; set; }
 | 
			
		||||
    public Account Account { get; set; } = null!;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public Ulid ApplicationId { get; set; }
 | 
			
		||||
    public Application Application { get; set; } = null!;
 | 
			
		||||
 | 
			
		||||
    public static (string, byte[]) Generate()
 | 
			
		||||
    {
 | 
			
		||||
        var token = CryptoUtils.RandomToken(48);
 | 
			
		||||
        var hash = SHA512.HashData(Convert.FromBase64String(token));
 | 
			
		||||
 | 
			
		||||
        return (token, hash);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue