mirror of
https://github.com/chylex/Minecraft-Phantom-Panel.git
synced 2025-05-05 03:34:05 +02:00
Fix web not checking permissions in events
This commit is contained in:
parent
8a87d7aff6
commit
c618a8d045
Server
Phantom.Server.Web.Identity/Authorization
Phantom.Server.Web
Utils/Phantom.Utils.Collections
@ -22,12 +22,12 @@ public sealed class PermissionManager {
|
||||
return new IdentityPermissions(userPermissions.Union(rolePermissions));
|
||||
}
|
||||
|
||||
private IdentityPermissions GetPermissionsForUserId(string? userId) {
|
||||
private IdentityPermissions GetPermissionsForUserId(string? userId, bool refreshCache) {
|
||||
if (userId == null) {
|
||||
return IdentityPermissions.None;
|
||||
}
|
||||
|
||||
if (userIdsToPermissionIds.TryGetValue(userId, out var userPermissions)) {
|
||||
if (!refreshCache && userIdsToPermissionIds.TryGetValue(userId, out var userPermissions)) {
|
||||
return userPermissions;
|
||||
}
|
||||
else {
|
||||
@ -35,11 +35,11 @@ public sealed class PermissionManager {
|
||||
}
|
||||
}
|
||||
|
||||
public IdentityPermissions GetPermissions(ClaimsPrincipal user) {
|
||||
return GetPermissionsForUserId(identityLookup.GetAuthenticatedUserId(user));
|
||||
public IdentityPermissions GetPermissions(ClaimsPrincipal user, bool refreshCache = false) {
|
||||
return GetPermissionsForUserId(identityLookup.GetAuthenticatedUserId(user), refreshCache);
|
||||
}
|
||||
|
||||
public bool CheckPermission(ClaimsPrincipal user, Permission permission) {
|
||||
return GetPermissions(user).Check(permission);
|
||||
public bool CheckPermission(ClaimsPrincipal user, Permission permission, bool refreshCache = false) {
|
||||
return GetPermissions(user, refreshCache).Check(permission);
|
||||
}
|
||||
}
|
||||
|
27
Server/Phantom.Server.Web/Base/PhantomComponent.cs
Normal file
27
Server/Phantom.Server.Web/Base/PhantomComponent.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Phantom.Common.Logging;
|
||||
using Phantom.Server.Web.Identity.Authorization;
|
||||
using Phantom.Server.Web.Identity.Data;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace Phantom.Server.Web.Base;
|
||||
|
||||
public abstract class PhantomComponent : ComponentBase {
|
||||
private static readonly ILogger Logger = PhantomLogger.Create<PhantomComponent>();
|
||||
|
||||
[CascadingParameter]
|
||||
public Task<AuthenticationState> AuthenticationStateTask { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
public PermissionManager PermissionManager { get; set; } = null!;
|
||||
|
||||
protected async Task<bool> CheckPermission(Permission permission) {
|
||||
var authenticationState = await AuthenticationStateTask;
|
||||
return PermissionManager.CheckPermission(authenticationState.User, permission, refreshCache: true);
|
||||
}
|
||||
|
||||
protected void InvokeAsyncChecked(Func<Task> task) {
|
||||
InvokeAsync(task).ContinueWith(static t => Logger.Error(t.Exception, "Caught exception in async task."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
@using Phantom.Common.Data.Replies
|
||||
@using Phantom.Server.Services.Audit
|
||||
@using Phantom.Server.Services.Instances
|
||||
@inherits PhantomComponent
|
||||
@inject InstanceManager InstanceManager
|
||||
@inject AuditLog AuditLog
|
||||
|
||||
@ -33,6 +34,11 @@
|
||||
private async Task ExecuteCommand(EditContext context) {
|
||||
await form.SubmitModel.StartSubmitting();
|
||||
|
||||
if (!await CheckPermission(Permission.ViewInstances)) {
|
||||
form.SubmitModel.StopSubmitting("You do not have permission to execute commands.");
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await InstanceManager.SendCommand(InstanceGuid, form.Command);
|
||||
if (result == SendCommandToInstanceResult.Success) {
|
||||
await AuditLog.AddInstanceCommandExecutedEvent(InstanceGuid, form.Command);
|
||||
|
@ -1,6 +1,8 @@
|
||||
@using Phantom.Server.Services.Instances
|
||||
@inherits PhantomComponent
|
||||
@using Phantom.Server.Services.Instances
|
||||
@using Phantom.Utils.Collections
|
||||
@using Phantom.Utils.Events
|
||||
@using System.Diagnostics
|
||||
@implements IDisposable
|
||||
@inject IJSRuntime Js;
|
||||
@inject InstanceLogManager InstanceLogManager
|
||||
@ -11,28 +13,30 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter, EditorRequired]
|
||||
public Guid InstanceGuid { get; set; }
|
||||
|
||||
|
||||
private IJSObjectReference? PageJs { get; set; }
|
||||
|
||||
private EventSubscribers<RingBuffer<string>> instanceLogsSubs = null!;
|
||||
private RingBuffer<string> instanceLogs = null!;
|
||||
|
||||
private readonly Stopwatch recheckPermissionsStopwatch = Stopwatch.StartNew();
|
||||
|
||||
protected override void OnInitialized() {
|
||||
instanceLogsSubs = InstanceLogManager.GetSubs(InstanceGuid);
|
||||
instanceLogsSubs.Subscribe(this, buffer => {
|
||||
instanceLogs = buffer;
|
||||
InvokeAsync(RefreshLog);
|
||||
InvokeAsyncChecked(RefreshLog);
|
||||
});
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
||||
if (firstRender) {
|
||||
PageJs = await Js.InvokeAsync<IJSObjectReference>("import", "./Shared/InstanceLog.razor.js");
|
||||
await RecheckPermissions();
|
||||
StateHasChanged();
|
||||
|
||||
await PageJs.InvokeVoidAsync("initLog");
|
||||
@ -40,6 +44,10 @@
|
||||
}
|
||||
|
||||
private async Task RefreshLog() {
|
||||
if (recheckPermissionsStopwatch.Elapsed > TimeSpan.FromSeconds(2)) {
|
||||
await RecheckPermissions();
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
|
||||
if (PageJs != null) {
|
||||
@ -47,7 +55,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RecheckPermissions() {
|
||||
recheckPermissionsStopwatch.Restart();
|
||||
|
||||
if (!await CheckPermission(Permission.ViewInstances)) {
|
||||
await Task.Yield();
|
||||
Dispose();
|
||||
instanceLogs = new RingBuffer<string>(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
instanceLogsSubs.Unsubscribe(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
@using Phantom.Server.Services.Instances
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using Phantom.Common.Data.Minecraft
|
||||
@inherits PhantomComponent
|
||||
@inject IJSRuntime Js;
|
||||
@inject InstanceManager InstanceManager;
|
||||
@inject AuditLog AuditLog
|
||||
@ -50,6 +51,11 @@
|
||||
private async Task StopInstance(EditContext context) {
|
||||
await form.SubmitModel.StartSubmitting();
|
||||
|
||||
if (!await CheckPermission(Permission.ViewInstances)) {
|
||||
form.SubmitModel.StopSubmitting("You do not have permission to stop instances.");
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await InstanceManager.StopInstance(InstanceGuid, new MinecraftStopStrategy(form.StopInSeconds));
|
||||
if (result == StopInstanceResult.StopInitiated) {
|
||||
await AuditLog.AddInstanceStoppedEvent(InstanceGuid, form.StopInSeconds);
|
||||
|
@ -1,6 +1,7 @@
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Phantom.Server.Services.Audit
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@inherits PhantomComponent
|
||||
@inject IJSRuntime Js;
|
||||
@inject UserManager<IdentityUser> UserManager
|
||||
@inject AuditLog AuditLog
|
||||
@ -51,6 +52,11 @@
|
||||
private async Task AddUser(EditContext context) {
|
||||
await form.SubmitModel.StartSubmitting();
|
||||
|
||||
if (!await CheckPermission(Permission.EditUsers)) {
|
||||
form.SubmitModel.StopSubmitting("You do not have permission to add users.");
|
||||
return;
|
||||
}
|
||||
|
||||
var user = new IdentityUser(form.Username);
|
||||
var result = await UserManager.CreateAsync(user, form.Password);
|
||||
if (result.Succeeded) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Phantom.Server.Services.Audit
|
||||
@inherits PhantomComponent
|
||||
@inject IJSRuntime Js;
|
||||
@inject UserManager<IdentityUser> UserManager
|
||||
@inject AuditLog AuditLog
|
||||
@ -38,6 +39,11 @@
|
||||
private async Task DeleteUser() {
|
||||
await submitModel.StartSubmitting();
|
||||
|
||||
if (!await CheckPermission(Permission.EditUsers)) {
|
||||
submitModel.StopSubmitting("You do not have permission to delete users.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (userToDelete == null) {
|
||||
submitModel.StopSubmitting("Invalid user.");
|
||||
return;
|
||||
|
@ -7,6 +7,7 @@
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using Phantom.Server.Web
|
||||
@using Phantom.Server.Web.Base
|
||||
@using Phantom.Server.Web.Components.Dialogs
|
||||
@using Phantom.Server.Web.Components.Forms
|
||||
@using Phantom.Server.Web.Components.Graphics
|
||||
|
@ -6,6 +6,10 @@ public sealed class RingBuffer<T> {
|
||||
private int writeIndex;
|
||||
|
||||
public RingBuffer(int capacity) {
|
||||
if (capacity < 0) {
|
||||
throw new ArgumentException("Capacity must not be negative.", nameof(capacity));
|
||||
}
|
||||
|
||||
this.buffer = new T[capacity];
|
||||
}
|
||||
|
||||
@ -19,6 +23,10 @@ public sealed class RingBuffer<T> {
|
||||
}
|
||||
|
||||
public void Add(T item) {
|
||||
if (Capacity == 0) {
|
||||
throw new InvalidOperationException("Ring buffer has no capacity.");
|
||||
}
|
||||
|
||||
buffer[writeIndex++] = item;
|
||||
Count = Math.Max(writeIndex, Count);
|
||||
writeIndex %= Capacity;
|
||||
@ -30,6 +38,10 @@ public sealed class RingBuffer<T> {
|
||||
}
|
||||
|
||||
public IEnumerable<T> EnumerateLast(uint maximumItems) {
|
||||
if (Capacity == 0) {
|
||||
yield break;
|
||||
}
|
||||
|
||||
int totalItemsToReturn = (int) Math.Min(maximumItems, Count);
|
||||
|
||||
// Yield items until we hit the end of the buffer.
|
||||
|
Loading…
Reference in New Issue
Block a user