mirror of
https://github.com/chylex/Minecraft-Phantom-Panel.git
synced 2025-05-08 12:34:03 +02:00
Minor code and dependency cleanup
This commit is contained in:
parent
2cc7975193
commit
b1758fb2bb
Agent
Phantom.Agent.Minecraft/Server
Phantom.Agent.Rpc
Phantom.Agent.Services/Rpc
Common
Server
Phantom.Server.Database/Entities
Phantom.Server.Rpc
Phantom.Server.Services
Phantom.Server.Web.Components/Utils
Phantom.Server.Web.Identity
Authentication
Authorization
Interfaces
Phantom.Server.Web.Identity.csprojPhantomIdentityConfigurator.csPhantomIdentityExtensions.csPhantomIdentityMiddleware.csPhantom.Server.Web
Utils/Phantom.Utils.IO
@ -6,10 +6,11 @@ using Serilog;
|
||||
|
||||
namespace Phantom.Agent.Minecraft.Server;
|
||||
|
||||
public sealed class MinecraftServerExecutables : IDisposable {
|
||||
public sealed partial class MinecraftServerExecutables : IDisposable {
|
||||
private static readonly ILogger Logger = PhantomLogger.Create<MinecraftServerExecutables>();
|
||||
|
||||
private static readonly Regex VersionFolderSanitizeRegex = new (@"[^a-zA-Z0-9_\-\.]", RegexOptions.Compiled);
|
||||
[GeneratedRegex(@"[^a-zA-Z0-9_\-\.]", RegexOptions.Compiled)]
|
||||
private static partial Regex VersionFolderSanitizeRegex();
|
||||
|
||||
private readonly string basePath;
|
||||
private readonly MinecraftVersions minecraftVersions = new ();
|
||||
@ -20,7 +21,7 @@ public sealed class MinecraftServerExecutables : IDisposable {
|
||||
}
|
||||
|
||||
internal async Task<string?> DownloadAndGetPath(string version, EventHandler<DownloadProgressEventArgs> progressEventHandler, CancellationToken cancellationToken) {
|
||||
string serverExecutableFolderPath = Path.Combine(basePath, VersionFolderSanitizeRegex.Replace(version, "_"));
|
||||
string serverExecutableFolderPath = Path.Combine(basePath, VersionFolderSanitizeRegex().Replace(version, "_"));
|
||||
string serverExecutableFilePath = Path.Combine(serverExecutableFolderPath, "server.jar");
|
||||
|
||||
if (File.Exists(serverExecutableFilePath)) {
|
||||
@ -49,7 +50,7 @@ public sealed class MinecraftServerExecutables : IDisposable {
|
||||
runningDownloadersByVersion.Remove(version);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
runningDownloadersByVersion[version] = downloader;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using NetMQ.Sockets;
|
||||
using Phantom.Common.Data.Agent;
|
||||
using Phantom.Common.Messages;
|
||||
using Phantom.Common.Messages.BiDirectional;
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Utils.Rpc;
|
||||
using Phantom.Utils.Rpc.Message;
|
||||
|
@ -1,7 +1,7 @@
|
||||
using NetMQ;
|
||||
using NetMQ.Sockets;
|
||||
using Phantom.Common.Messages;
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Common.Messages.BiDirectional;
|
||||
using Phantom.Utils.Rpc.Message;
|
||||
|
||||
namespace Phantom.Agent.Rpc;
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Common.Logging;
|
||||
using Phantom.Common.Messages;
|
||||
using Phantom.Common.Messages.BiDirectional;
|
||||
using Phantom.Common.Messages.ToAgent;
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Utils.Rpc.Message;
|
||||
|
@ -13,7 +13,7 @@ public sealed partial class AgentAuthToken {
|
||||
[MemoryPackInclude]
|
||||
private readonly byte[] bytes;
|
||||
|
||||
public AgentAuthToken(byte[]? bytes) {
|
||||
internal AgentAuthToken(byte[]? bytes) {
|
||||
if (bytes == null) {
|
||||
throw new ArgumentNullException(nameof(bytes));
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ using MemoryPack;
|
||||
namespace Phantom.Common.Data;
|
||||
|
||||
[MemoryPackable]
|
||||
public readonly partial record struct PortRange(
|
||||
readonly partial record struct PortRange(
|
||||
[property: MemoryPackOrder(0)] ushort FirstPort,
|
||||
[property: MemoryPackOrder(1)] ushort LastPort
|
||||
) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Phantom.Common.Data.Replies;
|
||||
|
||||
public enum ConfigureInstanceResult {
|
||||
public enum ConfigureInstanceResult : byte {
|
||||
Success,
|
||||
InstanceLimitExceeded,
|
||||
MemoryLimitExceeded
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Phantom.Common.Data.Replies;
|
||||
|
||||
public enum LaunchInstanceResult {
|
||||
public enum LaunchInstanceResult : byte {
|
||||
LaunchInitiated,
|
||||
InstanceAlreadyLaunching,
|
||||
InstanceAlreadyRunning,
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Phantom.Common.Data.Replies;
|
||||
|
||||
public enum SendCommandToInstanceResult {
|
||||
public enum SendCommandToInstanceResult : byte {
|
||||
Success,
|
||||
UnknownError
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Phantom.Common.Data.Replies;
|
||||
|
||||
public enum StopInstanceResult {
|
||||
public enum StopInstanceResult : byte {
|
||||
StopInitiated,
|
||||
InstanceAlreadyStopping,
|
||||
InstanceAlreadyStopped,
|
||||
|
@ -1,7 +1,7 @@
|
||||
using MemoryPack;
|
||||
using Phantom.Utils.Rpc.Message;
|
||||
|
||||
namespace Phantom.Common.Messages.ToServer;
|
||||
namespace Phantom.Common.Messages.BiDirectional;
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record ReplyMessage(
|
||||
|
@ -1,6 +1,6 @@
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Common.Messages.BiDirectional;
|
||||
using Phantom.Common.Messages.ToAgent;
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Utils.Rpc.Message;
|
||||
|
||||
namespace Phantom.Common.Messages;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Common.Messages.BiDirectional;
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Utils.Rpc.Message;
|
||||
|
||||
namespace Phantom.Common.Messages;
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Common.Logging;
|
||||
using Phantom.Common.Messages.BiDirectional;
|
||||
using Phantom.Common.Messages.ToAgent;
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Utils.Rpc.Message;
|
||||
|
@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
namespace Phantom.Server.Database.Entities;
|
||||
|
||||
[Table("Permissions", Schema = "identity")]
|
||||
public class PermissionEntity {
|
||||
public sealed class PermissionEntity {
|
||||
[Key]
|
||||
public string Id { get; set; }
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Phantom.Server.Database.Entities;
|
||||
|
||||
[Table("RolePermissions", Schema = "identity")]
|
||||
public class RolePermissionEntity {
|
||||
public sealed class RolePermissionEntity {
|
||||
public string RoleId { get; set; }
|
||||
public string PermissionId { get; set; }
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Phantom.Server.Database.Entities;
|
||||
|
||||
[Table("UserPermissions", Schema = "identity")]
|
||||
public class UserPermissionEntity {
|
||||
public sealed class UserPermissionEntity {
|
||||
public string UserId { get; set; }
|
||||
public string PermissionId { get; set; }
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
@ -6,10 +6,6 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Common\Phantom.Common.Messages\Phantom.Common.Messages.csproj" />
|
||||
</ItemGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
using NetMQ;
|
||||
using NetMQ.Sockets;
|
||||
using Phantom.Common.Messages;
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Common.Messages.BiDirectional;
|
||||
using Phantom.Utils.Rpc.Message;
|
||||
|
||||
namespace Phantom.Server.Rpc;
|
||||
|
@ -1,11 +1,12 @@
|
||||
using NetMQ.Sockets;
|
||||
using Phantom.Common.Messages;
|
||||
using Phantom.Common.Messages.BiDirectional;
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Utils.Rpc;
|
||||
using Phantom.Utils.Rpc.Message;
|
||||
using Phantom.Utils.Runtime;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace Phantom.Server.Rpc;
|
||||
|
||||
|
@ -10,7 +10,7 @@ using Phantom.Server.Services.Instances;
|
||||
using Phantom.Utils.Collections;
|
||||
using Phantom.Utils.Events;
|
||||
using Phantom.Utils.Runtime;
|
||||
using Serilog;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace Phantom.Server.Services.Agents;
|
||||
|
||||
|
@ -3,7 +3,7 @@ using Phantom.Common.Data;
|
||||
using Phantom.Common.Logging;
|
||||
using Phantom.Server.Services.Instances;
|
||||
using Phantom.Utils.Events;
|
||||
using Serilog;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace Phantom.Server.Services.Agents;
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Phantom.Server.Database.Enums;
|
||||
|
||||
namespace Phantom.Server.Services.Audit;
|
||||
@ -17,9 +16,8 @@ public sealed partial class AuditLog {
|
||||
AddEvent(userId, AuditEventType.UserLoggedIn, userId);
|
||||
}
|
||||
|
||||
public void AddUserLoggedOutEvent(ClaimsPrincipal user) {
|
||||
var userId = identityLookup.GetAuthenticatedUserId(user);
|
||||
AddEvent(userId, AuditEventType.UserLoggedOut, userId ?? string.Empty);
|
||||
public void AddUserLoggedOutEvent(string userId) {
|
||||
AddEvent(userId, AuditEventType.UserLoggedOut, userId);
|
||||
}
|
||||
|
||||
public Task AddUserCreatedEvent(IdentityUser user) {
|
||||
|
@ -3,7 +3,7 @@ using System.Collections.Immutable;
|
||||
using Phantom.Common.Logging;
|
||||
using Phantom.Utils.Collections;
|
||||
using Phantom.Utils.Events;
|
||||
using Serilog;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace Phantom.Server.Services.Instances;
|
||||
|
||||
|
@ -10,7 +10,7 @@ using Phantom.Server.Database.Entities;
|
||||
using Phantom.Server.Services.Agents;
|
||||
using Phantom.Utils.Collections;
|
||||
using Phantom.Utils.Events;
|
||||
using Serilog;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace Phantom.Server.Services.Instances;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
@ -6,6 +6,10 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Common\Phantom.Common.Data\Phantom.Common.Data.csproj" />
|
||||
<ProjectReference Include="..\..\Common\Phantom.Common.Minecraft\Phantom.Common.Minecraft.csproj" />
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Phantom.Common.Data.Instance;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Common.Messages;
|
||||
using Phantom.Common.Messages.BiDirectional;
|
||||
using Phantom.Common.Messages.ToAgent;
|
||||
using Phantom.Common.Messages.ToServer;
|
||||
using Phantom.Server.Rpc;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Phantom.Server.Web.Components.Utils;
|
||||
|
||||
public static class BootstrapEditContext {
|
||||
static class BootstrapEditContext {
|
||||
public static EditContext Create(object model) {
|
||||
EditContext context = new EditContext(model);
|
||||
context.SetFieldCssClassProvider(ClassProvider);
|
||||
|
@ -1,27 +1,35 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Phantom.Common.Logging;
|
||||
using Phantom.Server.Services.Audit;
|
||||
using Phantom.Server.Web.Identity.Interfaces;
|
||||
using Phantom.Utils.Cryptography;
|
||||
using Serilog;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace Phantom.Server.Web.Identity.Authentication;
|
||||
|
||||
public sealed class PhantomLoginManager {
|
||||
private static readonly ILogger Logger = PhantomLogger.Create<PhantomLoginManager>();
|
||||
|
||||
public static bool IsAuthenticated(ClaimsPrincipal user) {
|
||||
return user.Identity is { IsAuthenticated: true };
|
||||
}
|
||||
|
||||
internal static string? GetAuthenticatedUserId(ClaimsPrincipal user, UserManager<IdentityUser> userManager) {
|
||||
return IsAuthenticated(user) ? userManager.GetUserId(user) : null;
|
||||
}
|
||||
|
||||
private readonly INavigation navigation;
|
||||
private readonly PhantomLoginStore loginStore;
|
||||
private readonly UserManager<IdentityUser> userManager;
|
||||
private readonly SignInManager<IdentityUser> signInManager;
|
||||
private readonly AuditLog auditLog;
|
||||
private readonly ILoginEvents loginEvents;
|
||||
|
||||
public PhantomLoginManager(INavigation navigation, PhantomLoginStore loginStore, UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager, AuditLog auditLog) {
|
||||
public PhantomLoginManager(INavigation navigation, PhantomLoginStore loginStore, UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager, ILoginEvents loginEvents) {
|
||||
this.navigation = navigation;
|
||||
this.loginStore = loginStore;
|
||||
this.userManager = userManager;
|
||||
this.signInManager = signInManager;
|
||||
this.auditLog = auditLog;
|
||||
this.loginEvents = loginEvents;
|
||||
}
|
||||
|
||||
public async Task<SignInResult> SignIn(string username, string password, string? returnUrl = null) {
|
||||
@ -43,7 +51,10 @@ public sealed class PhantomLoginManager {
|
||||
}
|
||||
|
||||
internal async Task SignOut() {
|
||||
auditLog.AddUserLoggedOutEvent(signInManager.Context.User);
|
||||
if (GetAuthenticatedUserId(signInManager.Context.User, userManager) is {} userId) {
|
||||
loginEvents.UserLoggedOut(userId);
|
||||
}
|
||||
|
||||
await signInManager.SignOutAsync();
|
||||
}
|
||||
|
||||
@ -57,7 +68,7 @@ public sealed class PhantomLoginManager {
|
||||
var result = await signInManager.PasswordSignInAsync(user, entry.Password, lockoutOnFailure: false, isPersistent: true);
|
||||
if (result == SignInResult.Success) {
|
||||
Logger.Information("Successful login for {Username}.", user.UserName);
|
||||
auditLog.AddUserLoggedInEvent(user.Id);
|
||||
loginEvents.UserLoggedIn(user.Id);
|
||||
return entry.ReturnUrl;
|
||||
}
|
||||
else {
|
||||
|
@ -2,21 +2,24 @@
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Phantom.Common.Logging;
|
||||
using Phantom.Server.Services;
|
||||
using Phantom.Utils.Runtime;
|
||||
using Serilog;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace Phantom.Server.Web.Identity.Authentication;
|
||||
|
||||
public sealed class PhantomLoginStore {
|
||||
private static readonly ILogger Logger = PhantomLogger.Create<PhantomLoginStore>();
|
||||
private static readonly TimeSpan ExpirationTime = TimeSpan.FromMinutes(1);
|
||||
|
||||
|
||||
internal static Func<IServiceProvider, PhantomLoginStore> Create(CancellationToken cancellationToken) {
|
||||
return provider => new PhantomLoginStore(provider.GetRequiredService<TaskManager>(), cancellationToken);
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<string, LoginEntry> loginEntries = new ();
|
||||
private readonly CancellationToken cancellationToken;
|
||||
|
||||
public PhantomLoginStore(ServiceConfiguration configuration, TaskManager taskManager) {
|
||||
this.cancellationToken = configuration.CancellationToken;
|
||||
private PhantomLoginStore(TaskManager taskManager, CancellationToken cancellationToken) {
|
||||
this.cancellationToken = cancellationToken;
|
||||
taskManager.Run(RunExpirationLoop);
|
||||
}
|
||||
|
||||
|
@ -1,42 +1,40 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Phantom.Server.Database;
|
||||
using Phantom.Server.Services.Users;
|
||||
using Phantom.Server.Web.Identity.Authentication;
|
||||
using Phantom.Server.Web.Identity.Data;
|
||||
|
||||
namespace Phantom.Server.Web.Identity.Authorization;
|
||||
|
||||
public sealed class PermissionManager {
|
||||
private readonly DatabaseProvider databaseProvider;
|
||||
private readonly IdentityLookup identityLookup;
|
||||
private readonly UserManager<IdentityUser> userManager;
|
||||
private readonly Dictionary<string, IdentityPermissions> userIdsToPermissionIds = new ();
|
||||
|
||||
public PermissionManager(DatabaseProvider databaseProvider, IdentityLookup identityLookup) {
|
||||
public PermissionManager(DatabaseProvider databaseProvider, UserManager<IdentityUser> userManager) {
|
||||
this.databaseProvider = databaseProvider;
|
||||
this.identityLookup = identityLookup;
|
||||
this.userManager = userManager;
|
||||
}
|
||||
|
||||
private IdentityPermissions FetchPermissions(string userId) {
|
||||
private IdentityPermissions FetchPermissionsForUserId(string userId) {
|
||||
using var scope = databaseProvider.CreateScope();
|
||||
var userPermissions = scope.Ctx.UserPermissions.Where(up => up.UserId == userId).Select(static up => up.PermissionId);
|
||||
var rolePermissions = scope.Ctx.UserRoles.Where(ur => ur.UserId == userId).Join(scope.Ctx.RolePermissions, static ur => ur.RoleId, static rp => rp.RoleId, static (ur, rp) => rp.PermissionId);
|
||||
return new IdentityPermissions(userPermissions.Union(rolePermissions));
|
||||
}
|
||||
|
||||
private IdentityPermissions GetPermissionsForUserId(string? userId, bool refreshCache) {
|
||||
if (userId == null) {
|
||||
return IdentityPermissions.None;
|
||||
}
|
||||
|
||||
private IdentityPermissions GetPermissionsForUserId(string userId, bool refreshCache) {
|
||||
if (!refreshCache && userIdsToPermissionIds.TryGetValue(userId, out var userPermissions)) {
|
||||
return userPermissions;
|
||||
}
|
||||
else {
|
||||
return userIdsToPermissionIds[userId] = FetchPermissions(userId);
|
||||
return userIdsToPermissionIds[userId] = FetchPermissionsForUserId(userId);
|
||||
}
|
||||
}
|
||||
|
||||
public IdentityPermissions GetPermissions(ClaimsPrincipal user, bool refreshCache = false) {
|
||||
return GetPermissionsForUserId(identityLookup.GetAuthenticatedUserId(user), refreshCache);
|
||||
string? userId = PhantomLoginManager.GetAuthenticatedUserId(user, userManager);
|
||||
return userId == null ? IdentityPermissions.None : GetPermissionsForUserId(userId, refreshCache);
|
||||
}
|
||||
|
||||
public bool CheckPermission(ClaimsPrincipal user, Permission permission, bool refreshCache = false) {
|
||||
|
@ -0,0 +1,6 @@
|
||||
namespace Phantom.Server.Web.Identity.Interfaces;
|
||||
|
||||
public interface ILoginEvents {
|
||||
void UserLoggedIn(string userId);
|
||||
void UserLoggedOut(string userId);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Phantom.Server.Web.Identity;
|
||||
namespace Phantom.Server.Web.Identity.Interfaces;
|
||||
|
||||
public interface INavigation {
|
||||
string BasePath { get; }
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
@ -6,6 +6,10 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
@ -16,7 +20,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Phantom.Server.Services\Phantom.Server.Services.csproj" />
|
||||
<ProjectReference Include="..\..\Common\Phantom.Common.Logging\Phantom.Common.Logging.csproj" />
|
||||
<ProjectReference Include="..\..\Utils\Phantom.Utils.Cryptography\Phantom.Utils.Cryptography.csproj" />
|
||||
<ProjectReference Include="..\..\Utils\Phantom.Utils.Runtime\Phantom.Utils.Runtime.csproj" />
|
||||
<ProjectReference Include="..\Phantom.Server.Database\Phantom.Server.Database.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,12 +1,11 @@
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Phantom.Common.Logging;
|
||||
using Phantom.Server.Database;
|
||||
using Phantom.Server.Database.Entities;
|
||||
using Phantom.Server.Web.Identity.Data;
|
||||
using Phantom.Utils.Runtime;
|
||||
using Serilog;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace Phantom.Server.Web.Identity;
|
||||
|
||||
|
@ -13,13 +13,13 @@ using Phantom.Server.Web.Identity.Data;
|
||||
namespace Phantom.Server.Web.Identity;
|
||||
|
||||
public static class PhantomIdentityExtensions {
|
||||
public static void AddPhantomIdentity<TUser, TRole>(this IServiceCollection services) where TUser : class where TRole : class {
|
||||
public static void AddPhantomIdentity<TUser, TRole>(this IServiceCollection services, CancellationToken cancellationToken) where TUser : class where TRole : class {
|
||||
services.AddIdentity<TUser, TRole>(ConfigureIdentity).AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
services.ConfigureApplicationCookie(ConfigureIdentityCookie);
|
||||
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
services.AddAuthorization(ConfigureAuthorization);
|
||||
|
||||
services.AddSingleton<PhantomLoginStore>();
|
||||
services.AddSingleton(PhantomLoginStore.Create(cancellationToken));
|
||||
services.AddScoped<PhantomLoginManager>();
|
||||
|
||||
services.AddScoped<PhantomIdentityConfigurator>();
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Phantom.Server.Web.Identity.Authentication;
|
||||
using Phantom.Server.Web.Identity.Interfaces;
|
||||
|
||||
namespace Phantom.Server.Web.Identity;
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
@inject INavigation Nav
|
||||
@using Phantom.Server.Web.Identity.Interfaces
|
||||
@using Phantom.Server.Web.Identity.Authentication
|
||||
@inject INavigation Nav
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<CascadingAuthenticationState>
|
||||
@ -6,7 +8,7 @@
|
||||
<Found Context="routeData">
|
||||
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
|
||||
<NotAuthorized>
|
||||
@if (context.User.Identity is not { IsAuthenticated: true }) {
|
||||
@if (!PhantomLoginManager.IsAuthenticated(context.User)) {
|
||||
var returnUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri).TrimEnd('/');
|
||||
Nav.NavigateTo("login" + QueryString.Create("return", returnUrl), forceLoad: true);
|
||||
}
|
||||
|
20
Server/Phantom.Server.Web/Base/LoginEvents.cs
Normal file
20
Server/Phantom.Server.Web/Base/LoginEvents.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using Phantom.Server.Services.Audit;
|
||||
using Phantom.Server.Web.Identity.Interfaces;
|
||||
|
||||
namespace Phantom.Server.Web.Base;
|
||||
|
||||
sealed class LoginEvents : ILoginEvents {
|
||||
private readonly AuditLog auditLog;
|
||||
|
||||
public LoginEvents(AuditLog auditLog) {
|
||||
this.auditLog = auditLog;
|
||||
}
|
||||
|
||||
public void UserLoggedIn(string userId) {
|
||||
auditLog.AddUserLoggedInEvent(userId);
|
||||
}
|
||||
|
||||
public void UserLoggedOut(string userId) {
|
||||
auditLog.AddUserLoggedOutEvent(userId);
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Web;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Phantom.Server.Web.Identity;
|
||||
using Phantom.Server.Web.Identity.Interfaces;
|
||||
|
||||
namespace Phantom.Server.Web;
|
||||
namespace Phantom.Server.Web.Base;
|
||||
|
||||
sealed class Navigation : INavigation {
|
||||
public static Func<IServiceProvider, Navigation> Create(string basePath) {
|
@ -2,8 +2,10 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Phantom.Server.Database;
|
||||
using Phantom.Server.Web.Base;
|
||||
using Phantom.Server.Web.Components.Utils;
|
||||
using Phantom.Server.Web.Identity;
|
||||
using Phantom.Server.Web.Identity.Interfaces;
|
||||
using Serilog;
|
||||
|
||||
namespace Phantom.Server.Web;
|
||||
@ -35,7 +37,8 @@ public static class Launcher {
|
||||
builder.Services.AddDbContextPool<ApplicationDbContext>(dbOptionsBuilder, poolSize: 64);
|
||||
builder.Services.AddSingleton<DatabaseProvider>();
|
||||
|
||||
builder.Services.AddPhantomIdentity<IdentityUser, IdentityRole>();
|
||||
builder.Services.AddPhantomIdentity<IdentityUser, IdentityRole>(config.CancellationToken);
|
||||
builder.Services.AddScoped<ILoginEvents, LoginEvents>();
|
||||
|
||||
builder.Services.AddRazorPages(static options => options.RootDirectory = "/Layout");
|
||||
builder.Services.AddServerSideBlazor();
|
||||
|
@ -1,5 +1,5 @@
|
||||
@page
|
||||
@using Phantom.Server.Web.Identity
|
||||
@using Phantom.Server.Web.Identity.Interfaces
|
||||
@model Phantom.Server.Web.Layout.ErrorModel
|
||||
@inject INavigation Navigation
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@using Phantom.Server.Web.Identity
|
||||
@using Phantom.Server.Web.Identity.Interfaces
|
||||
@namespace Phantom.Server.Web.Layout
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@inject INavigation Navigation
|
||||
|
@ -8,6 +8,7 @@
|
||||
@using System.Collections.Immutable
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using System.Diagnostics.CodeAnalysis
|
||||
@using Phantom.Server.Web.Identity.Interfaces
|
||||
@using Phantom.Common.Data.Java
|
||||
@using Phantom.Common.Data
|
||||
@using Phantom.Common.Data.Instance
|
||||
|
@ -1,4 +1,5 @@
|
||||
@page "/login"
|
||||
@using Phantom.Server.Web.Identity.Interfaces
|
||||
@using Phantom.Server.Web.Identity.Authentication
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
|
@ -28,8 +28,9 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@{ var myUserId = IdentityLookup.GetAuthenticatedUserId(context.User); }
|
||||
@foreach (var user in allUsers) {
|
||||
var isMe = IdentityLookup.GetAuthenticatedUserId(context.User) == user.Id;
|
||||
var isMe = myUserId == user.Id;
|
||||
<tr>
|
||||
<td>
|
||||
<code class="text-uppercase">@user.Id</code>
|
||||
|
@ -1,18 +1,12 @@
|
||||
namespace Phantom.Utils.IO;
|
||||
|
||||
public readonly record struct FileSize {
|
||||
public readonly record struct FileSize(ulong Bytes) {
|
||||
private const int Scale = 1024;
|
||||
|
||||
private static readonly string[] Units = {
|
||||
"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"
|
||||
};
|
||||
|
||||
public ulong Bytes { get; }
|
||||
|
||||
public FileSize(ulong bytes) {
|
||||
Bytes = bytes;
|
||||
}
|
||||
|
||||
public string ToHumanReadable(int decimalPlaces) {
|
||||
int power = Bytes == 0L ? 0 : (int) Math.Log(Bytes, Scale);
|
||||
int unit = power >= Units.Length ? Units.Length - 1 : power;
|
||||
|
Loading…
Reference in New Issue
Block a user