using HyperBooru.Services; using Microsoft.AspNetCore.Cryptography.KeyDerivation; using Microsoft.EntityFrameworkCore; namespace HyperBooru.PrincipalProviders; public class LocalPrincipalProvider : PrincipalProvider { private IDbContextFactory dbFactory; public LocalPrincipalProvider(IDbContextFactory dbFactory) => this.dbFactory = dbFactory; public override IPrincipal? GetPrincipal(string name) { using var db = dbFactory.CreateDbContext(); return db.Principals.FirstOrDefault(p => p.Name == name); } public override IUser? GetUser(string name) { using var db = dbFactory.CreateDbContext(); return db.Users.FirstOrDefault(p => p.Name == name); } public override IGroup? GetGroup(string name) { using var db = dbFactory.CreateDbContext(); return db.Groups.FirstOrDefault(p => p.Name == name); } public override IGroup[] GetGroups(SecurityIdentifier sid, bool recurse) { using var db = dbFactory.CreateDbContext(); List groups = db.Principals .First(p => p.Sid == sid) .MemberOf; if(!recurse) return groups.ToArray(); var allGroups = db.Groups .Include(g => g.MemberOf) .ToArray(); groups = allGroups .IntersectBy(groups.Select(g => g.Sid), g => g.Sid) .ToList(); while(true) { var toAdd = groups .SelectMany(g => g.MemberOf) .ExceptBy(groups.Select(g => g.Sid), g => g.Sid) .ToArray(); if(toAdd.Count() == 0) break; groups.AddRange(toAdd); } return groups.ToArray(); } public override bool ValidatePassword(IUser user, string password) => ((LocalUser) user).PasswordHash == HashPassword(password); public static string HashPassword(string password) => Convert.ToBase64String( KeyDerivation.Pbkdf2( password, Array.Empty(), KeyDerivationPrf.HMACSHA512, 100_000, 512 / 8)); }