Initial commit
This commit is contained in:
94
Backend/Repositorys/GroupRepository.cs
Normal file
94
Backend/Repositorys/GroupRepository.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using Backend.Entitys;
|
||||
|
||||
namespace Backend.Repositorys;
|
||||
|
||||
public class GroupRepository {
|
||||
public static PermissionGroup[] Groups;
|
||||
|
||||
public static void CompileGroups(IConfiguration configuration) {
|
||||
var groupsSections = configuration.GetSection("Groups").GetChildren();
|
||||
List<PermissionGroup> groups = new List<PermissionGroup>();
|
||||
foreach (var section in groupsSections) {
|
||||
PermissionGroup group = new PermissionGroup();
|
||||
group.Name = section.GetValue<string>("Name");
|
||||
group.Permission = section.GetValue<string>("Permission");
|
||||
group.Permissions = section.GetSection("Permissions").Get<string[]>();
|
||||
group.Inherits = section.GetSection("Inherits").Get<string[]>();
|
||||
groups.Add(group);
|
||||
}
|
||||
Groups = groups.ToArray();
|
||||
}
|
||||
|
||||
private readonly DatabaseContext _context;
|
||||
private readonly PermissionGroup[] _groups;
|
||||
|
||||
public GroupRepository(DatabaseContext context) {
|
||||
_context = context;
|
||||
_groups = Groups;
|
||||
}
|
||||
|
||||
public PermissionGroup GetPermissionGroup(string name) {
|
||||
return _groups.SingleOrDefault(group => group.Permission.Equals(name));
|
||||
}
|
||||
|
||||
public PermissionGroup[] GetGroupsFromUser(Guid userId) {
|
||||
Permission[] permissions = GetUserPermissionsRaw(userId).ToArray();
|
||||
return ExtractGroups(permissions);
|
||||
}
|
||||
|
||||
public PermissionGroup[] ExtractGroups(Permission[] permissions) {
|
||||
List<PermissionGroup> permissionGroups = new List<PermissionGroup>();
|
||||
foreach (var permission in permissions) {
|
||||
if (permission.PermissionKey.StartsWith("group.")) {
|
||||
foreach (var permissionGroup in _groups) {
|
||||
if (permission.PermissionKey.Equals(permissionGroup.Permission)) {
|
||||
permissionGroups.Add(permissionGroup);
|
||||
|
||||
if (permissionGroup.Inherits is not null) {
|
||||
foreach (var inherit in permissionGroup.Inherits) {
|
||||
permissionGroups.Add(GetPermissionGroup(inherit));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return permissionGroups.ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<Permission> GetUserPermissions(Guid userId) {
|
||||
List<Permission> permissions = GetUserPermissionsRaw(userId).ToList();
|
||||
|
||||
PermissionGroup[] groups = ExtractGroups(permissions.ToArray());
|
||||
foreach (var group in groups) {
|
||||
if (group.Permissions is null) continue;
|
||||
permissions.AddRange(group.Permissions
|
||||
.Select(perm => new Permission { Id = -1, UserId = userId, PermissionKey = perm }));
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public IEnumerable<Permission> GetUserPermissionsRaw(Guid userId) {
|
||||
return _context.Permissions.Where(permission => permission.UserId == userId);
|
||||
}
|
||||
|
||||
public void AddPermissions(Guid userId, params string[] permissions) {
|
||||
foreach (var permission in permissions) {
|
||||
_context.Permissions.Add(new Permission
|
||||
{ PermissionKey = permission, UserId = userId });
|
||||
}
|
||||
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
public void DeletePermissions(Guid userId, params string[] permissions) {
|
||||
foreach (var permission in permissions) {
|
||||
_context.Permissions.RemoveRange(_context.Permissions.Where(perm =>
|
||||
perm.UserId == userId && perm.PermissionKey == permission));
|
||||
}
|
||||
|
||||
_context.SaveChanges();
|
||||
}
|
||||
}
|
||||
92
Backend/Repositorys/TokenRepository.cs
Normal file
92
Backend/Repositorys/TokenRepository.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System.Text;
|
||||
using Backend.Entitys;
|
||||
using Backend.Security.Authentication;
|
||||
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Backend.Repositorys;
|
||||
|
||||
public class TokenRepository {
|
||||
private readonly JwtTokenAuthenticationOptions _options;
|
||||
private readonly DatabaseContext _context;
|
||||
|
||||
public TokenRepository(IOptions<JwtTokenAuthenticationOptions> options, DatabaseContext context) {
|
||||
_options = options.Value;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public RefreshToken GetRefreshToken(Guid refreshTokenId) {
|
||||
if (string.IsNullOrEmpty(refreshTokenId.ToString())) return null;
|
||||
return _context.RefreshTokens.SingleOrDefault(token => token.Id == refreshTokenId);
|
||||
}
|
||||
|
||||
public AccessToken GetAccessToken(Guid accessTokenId) {
|
||||
if (string.IsNullOrEmpty(accessTokenId.ToString())) return null;
|
||||
return _context.AccessTokens.SingleOrDefault(token => token.Id == accessTokenId);
|
||||
}
|
||||
|
||||
public IEnumerable<AccessToken> GetAccessTokens(Guid refreshTokenId) {
|
||||
if (string.IsNullOrEmpty(refreshTokenId.ToString())) return ArraySegment<AccessToken>.Empty;
|
||||
return _context.AccessTokens.Where(token => token.RefreshTokenId == refreshTokenId);
|
||||
}
|
||||
|
||||
public bool ValidateAccessToken(Guid accessTokenId) {
|
||||
AccessToken token = GetAccessToken(accessTokenId);
|
||||
if (token == null) return false;
|
||||
TimeSpan span = token.ExpirationDate - DateTime.Now;
|
||||
return span.TotalMilliseconds > 0;
|
||||
}
|
||||
|
||||
public bool ValidateRefreshToken(Guid refreshTokenId) {
|
||||
RefreshToken token = GetRefreshToken(refreshTokenId);
|
||||
if (token == null) return false;
|
||||
TimeSpan span = token.ExpirationDate - DateTime.Now;
|
||||
return span.TotalMilliseconds > 0;
|
||||
}
|
||||
|
||||
public RefreshToken CreateRefreshToken(Guid userId) {
|
||||
RefreshToken token = new RefreshToken {
|
||||
UserId = userId, Id = Guid.NewGuid(),
|
||||
ExpirationDate = DateTime.Now.Add(new TimeSpan(int.Parse(_options.RefreshTokenExpirationTimeInHours), 0, 0))
|
||||
};
|
||||
_context.RefreshTokens.Add(token);
|
||||
_context.SaveChanges();
|
||||
return token;
|
||||
}
|
||||
|
||||
public AccessToken CreateAccessToken(Guid refreshTokenId) {
|
||||
AccessToken token = new AccessToken {
|
||||
RefreshTokenId = refreshTokenId, Id = Guid.NewGuid(),
|
||||
ExpirationDate = DateTime.Now
|
||||
.Add(new TimeSpan(0, int.Parse(_options.AccessTokenExpirationTimeInMinutes), 0))
|
||||
};
|
||||
_context.AccessTokens.Add(token);
|
||||
_context.SaveChanges();
|
||||
return token;
|
||||
}
|
||||
|
||||
public void DeleteUserTokens(Guid userId) {
|
||||
List<RefreshToken> refreshTokens = _context.RefreshTokens.Where(token => token.UserId == userId).ToList();
|
||||
refreshTokens.ForEach(token => DeleteRefreshToken(token.Id));
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
public void DeleteRefreshToken(Guid refreshTokenId) {
|
||||
_context.RefreshTokens.RemoveRange(_context.RefreshTokens.Where(token => token.Id == refreshTokenId));
|
||||
_context.AccessTokens.RemoveRange(_context.AccessTokens.Where(token => token.RefreshTokenId == refreshTokenId));
|
||||
}
|
||||
|
||||
public static string Hash128(string plainText, string salt) {
|
||||
try {
|
||||
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
|
||||
password: plainText,
|
||||
salt: Encoding.Default.GetBytes(salt),
|
||||
prf: KeyDerivationPrf.HMACSHA256,
|
||||
iterationCount: 100000,
|
||||
numBytesRequested: 256 / 8
|
||||
));
|
||||
|
||||
return hashed;
|
||||
} catch (Exception) { return ""; }
|
||||
}
|
||||
}
|
||||
68
Backend/Repositorys/UserRepository.cs
Normal file
68
Backend/Repositorys/UserRepository.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using Backend.Entitys;
|
||||
using Backend.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Backend.Repositorys;
|
||||
|
||||
public class UserRepository {
|
||||
private DatabaseContext _context;
|
||||
private TokenRepository _tokens;
|
||||
private GroupRepository _groups;
|
||||
private UserOptions _options;
|
||||
|
||||
public UserRepository(DatabaseContext context, TokenRepository tokens, GroupRepository groups, IOptions<UserOptions> options) {
|
||||
_context = context;
|
||||
_tokens = tokens;
|
||||
_groups = groups;
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
public IEnumerable<User> GetUsers() => _context.Users.OrderBy(user => user.Created);
|
||||
|
||||
public User GetUser(Guid userId) => _context.Users.SingleOrDefault(user => user.Id == userId);
|
||||
|
||||
public User CreateUser(UserEditor editor) {
|
||||
var user = new User {
|
||||
Id = Guid.NewGuid(),
|
||||
Created = DateTime.Now,
|
||||
|
||||
Email = editor.Email,
|
||||
FirstName = editor.FirstName,
|
||||
LastName = editor.LastName,
|
||||
Password = TokenRepository.Hash128(editor.Password, editor.Email),
|
||||
Username = editor.Username
|
||||
};
|
||||
|
||||
_context.Users.Add(user);
|
||||
_context.SaveChanges();
|
||||
_groups.AddPermissions(user.Id, _options.DefaultPermissions);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public void EditUser(Guid userId, UserEditor editor) {
|
||||
var user = GetUser(userId);
|
||||
|
||||
string SetValue(string orig, string input, string hashed = null) {
|
||||
if (!string.IsNullOrEmpty(input))
|
||||
return !string.IsNullOrEmpty(hashed) ? hashed : input;
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
user.Email = SetValue(user.Email, editor.Email);
|
||||
user.FirstName = SetValue(user.FirstName, editor.FirstName);
|
||||
user.LastName = SetValue(user.LastName, editor.LastName);
|
||||
user.Username = SetValue(user.Username, editor.Username);
|
||||
user.Password = SetValue(user.Password, editor.Password, TokenRepository.Hash128(editor.Password, editor.Email));
|
||||
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
public void DeleteUser(Guid userId) {
|
||||
_context.Users.Remove(_context.Users.Single(user => user.Id == userId));
|
||||
_context.Permissions.RemoveRange(_context.Permissions.Where(perm => perm.UserId == userId));
|
||||
_tokens.DeleteUserTokens(userId);
|
||||
_context.SaveChanges();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user