Fixed jwt validation error. Added node allocations editor. Small fixes
This commit is contained in:
parent
70445069fd
commit
1b427607d1
11 changed files with 235 additions and 19 deletions
|
@ -75,7 +75,7 @@ public class IdentityService
|
|||
if (string.IsNullOrEmpty(Token))
|
||||
return;
|
||||
|
||||
if (!await JwtService.Validate(Token))
|
||||
if (!await JwtService.Validate(Token, "User"))
|
||||
return;
|
||||
|
||||
var data = await JwtService.Decode(Token);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using JWT.Algorithms;
|
||||
using JWT.Builder;
|
||||
using JWT.Exceptions;
|
||||
using MoonCore.Attributes;
|
||||
using MoonCore.Helpers;
|
||||
using MoonCore.Services;
|
||||
|
@ -43,6 +44,14 @@ public class JwtService
|
|||
{
|
||||
try
|
||||
{
|
||||
// Without the body decode call the jwt validation would not work for some weird reason.
|
||||
// It would not throw an error when the signature is invalid
|
||||
_ = new JwtBuilder()
|
||||
.WithSecret(ConfigService.Get().Security.Token)
|
||||
.WithAlgorithm(new HMACSHA512Algorithm())
|
||||
.MustVerifySignature()
|
||||
.Decode(token);
|
||||
|
||||
var headerJson = new JwtBuilder()
|
||||
.WithSecret(ConfigService.Get().Security.Token)
|
||||
.WithAlgorithm(new HMACSHA512Algorithm())
|
||||
|
@ -51,28 +60,34 @@ public class JwtService
|
|||
|
||||
if (headerJson == null)
|
||||
return Task.FromResult(false);
|
||||
|
||||
|
||||
// Jwt type validation
|
||||
if(allowedJwtTypes.Length == 0)
|
||||
if (allowedJwtTypes.Length == 0)
|
||||
return Task.FromResult(true);
|
||||
|
||||
|
||||
var headerData = JsonConvert.DeserializeObject<Dictionary<string, string>>(headerJson);
|
||||
|
||||
if(headerData == null) // => Invalid header
|
||||
|
||||
if (headerData == null) // => Invalid header
|
||||
return Task.FromResult(false);
|
||||
|
||||
if(!headerData.ContainsKey("Type")) // => Invalid header, Type is missing
|
||||
|
||||
if (!headerData.ContainsKey("Type")) // => Invalid header, Type is missing
|
||||
return Task.FromResult(false);
|
||||
|
||||
foreach (var name in allowedJwtTypes)
|
||||
{
|
||||
if(headerData["Type"] == name) // => Correct type found
|
||||
if (headerData["Type"] == name) // => Correct type found
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
|
||||
// None found? Invalid type!
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
catch (SignatureVerificationException)
|
||||
{
|
||||
Logger.Warn($"A manipulated jwt has been found. Required jwt types: {string.Join(" ", allowedJwtTypes)} Jwt: {token}");
|
||||
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warn(e.Message);
|
||||
|
@ -91,11 +106,17 @@ public class JwtService
|
|||
.Decode(token);
|
||||
|
||||
var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
|
||||
|
||||
|
||||
return Task.FromResult(data)!;
|
||||
}
|
||||
catch (Exception)
|
||||
catch (SignatureVerificationException)
|
||||
{
|
||||
return Task.FromResult(new Dictionary<string, string>());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warn("An unknown error occured while processing token");
|
||||
Logger.Warn(e);
|
||||
return Task.FromResult<Dictionary<string, string>>(null!);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
Sign In
|
||||
</h1>
|
||||
<div class="text-gray-400 fw-semibold fs-6">
|
||||
Get unlimited access & earn money
|
||||
Change me
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
Sign Up
|
||||
</h1>
|
||||
<div class="text-gray-400 fw-semibold fs-6">
|
||||
Get unlimited access & earn money
|
||||
change me
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System.Net.Sockets;
|
||||
using MoonCore.Abstractions;
|
||||
using MoonCore.Attributes;
|
||||
using MoonCore.Helpers;
|
||||
|
@ -32,6 +33,16 @@ public class InitBackgroundService : BackgroundService
|
|||
{
|
||||
await nodeService.Boot(node);
|
||||
}
|
||||
catch (HttpRequestException e)
|
||||
{
|
||||
if(e.InnerException is SocketException socketException)
|
||||
Logger.Warn($"Unable to auto boot node '{node.Name}'. Unable to reach the daemon: {socketException.Message}");
|
||||
else
|
||||
{
|
||||
Logger.Warn($"An error occured while booting node '{node.Name}'");
|
||||
Logger.Warn(e);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warn($"An error occured while booting node '{node.Name}'");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.Features.Servers.Models.Forms.Admin;
|
||||
namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes;
|
||||
|
||||
public class CreateNodeForm
|
||||
{
|
|
@ -0,0 +1,12 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes;
|
||||
|
||||
public class CreateServerAllocation
|
||||
{
|
||||
[Required(ErrorMessage = "You need to provide a bind ip address")]
|
||||
public string IpAddress { get; set; } = "0.0.0.0";
|
||||
|
||||
[Range(1, 65535, ErrorMessage = "You need to provide a valid port")]
|
||||
public int Port { get; set; }
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.Features.Servers.Models.Forms.Admin;
|
||||
namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes;
|
||||
|
||||
public class UpdateNodeForm
|
||||
{
|
|
@ -0,0 +1,12 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes;
|
||||
|
||||
public class UpdateServerAllocation
|
||||
{
|
||||
[Required(ErrorMessage = "You need to provide a bind ip address")]
|
||||
public string IpAddress { get; set; } = "0.0.0.0";
|
||||
|
||||
[Range(1, 65535, ErrorMessage = "You need to provide a valid port")]
|
||||
public int Port { get; set; }
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
@using MoonCore.Abstractions
|
||||
@using MoonCore.Exceptions
|
||||
@using MoonCore.Helpers
|
||||
@using Moonlight.Features.Servers.Models.Forms.Admin.Nodes
|
||||
|
||||
@attribute [RequirePermission(Permission.AdminServers)]
|
||||
|
||||
|
|
|
@ -1,7 +1,166 @@
|
|||
@page "/admin/servers/nodes/{Id:int}"
|
||||
|
||||
@using BlazorTable
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using MoonCore.Abstractions
|
||||
@using MoonCore.Exceptions
|
||||
@using MoonCoreUI.Services
|
||||
@using Moonlight.Features.Servers.Entities
|
||||
@using Moonlight.Features.Servers.Models.Forms.Admin.Nodes
|
||||
|
||||
@inject Repository<ServerNode> NodeRepository
|
||||
@inject Repository<Server> ServerRepository
|
||||
@inject Repository<ServerAllocation> AllocationRepository
|
||||
@inject ToastService ToastService
|
||||
@inject AlertService AlertService
|
||||
|
||||
<LazyLoader @ref="LazyLoader" Load="Load" ShowAsCard="true">
|
||||
@if (Node == null)
|
||||
{
|
||||
<NotFoundAlert/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-12 mb-5">
|
||||
|
||||
</div>
|
||||
<div class="col-md-6 col-12 mb-5">
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<span class="card-title">Allocation Quick Add</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="input-group me-1">
|
||||
<input @bind="AllocationStart" class="form-control w-25" type="number"/>
|
||||
<span class="input-group-text">-</span>
|
||||
<input @bind="AllocationEnd" class="form-control w-25" type="number"/>
|
||||
<WButton OnClick="AddAllocations" Text="Add" CssClasses="btn btn-primary"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AutoListCrud TItem="ServerAllocation"
|
||||
TRootItem="ServerNode"
|
||||
TCreateForm="CreateServerAllocation"
|
||||
TUpdateForm="UpdateServerAllocation"
|
||||
RootItem="Node"
|
||||
Field="@(x => x.Allocations)"
|
||||
Title="Allocations"
|
||||
ValidateAdd="ValidateAdd"
|
||||
ValidateUpdate="ValidateUpdate"
|
||||
ValidateDelete="ValidateDelete">
|
||||
<Toolbar>
|
||||
<div class="me-1">
|
||||
<WButton OnClick="DeleteAllAllocations" CssClasses="btn btn-icon btn-danger">
|
||||
<i class="bx bx-sm bx-trash"></i>
|
||||
</WButton>
|
||||
</div>
|
||||
</Toolbar>
|
||||
<View>
|
||||
<Column TableItem="ServerAllocation" Field="@(x => x.Id)" Title="Id"/>
|
||||
<Column TableItem="ServerAllocation" Field="@(x => x.IpAddress)" Title="IpAddress"/>
|
||||
<Column TableItem="ServerAllocation" Field="@(x => x.Port)" Title="Port"/>
|
||||
</View>
|
||||
</AutoListCrud>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</LazyLoader>
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter]
|
||||
public int Id { get; set; }
|
||||
}
|
||||
[Parameter] public int Id { get; set; }
|
||||
|
||||
private ServerNode? Node;
|
||||
private int AllocationStart = 2000;
|
||||
private int AllocationEnd = 3000;
|
||||
|
||||
private LazyLoader LazyLoader;
|
||||
|
||||
private async Task Load(LazyLoader lazyLoader)
|
||||
{
|
||||
await lazyLoader.SetText("Loading allocations");
|
||||
|
||||
Node = NodeRepository
|
||||
.Get()
|
||||
.Include(x => x.Allocations)
|
||||
.FirstOrDefault(x => x.Id == Id);
|
||||
}
|
||||
|
||||
private async Task AddAllocations()
|
||||
{
|
||||
int skipped = 0;
|
||||
int added = 0;
|
||||
|
||||
for (int i = AllocationStart; i <= AllocationEnd; i++)
|
||||
{
|
||||
if (Node!.Allocations.Any(x => x.Port == i))
|
||||
skipped++;
|
||||
else
|
||||
{
|
||||
Node.Allocations.Add(new()
|
||||
{
|
||||
Port = i
|
||||
});
|
||||
|
||||
added++;
|
||||
}
|
||||
}
|
||||
|
||||
NodeRepository.Update(Node!);
|
||||
|
||||
await ToastService.Success($"Added {added} allocations and skipped {skipped} ports due to existing allocations");
|
||||
await LazyLoader.Reload();
|
||||
}
|
||||
|
||||
private Task ValidateAdd(ServerAllocation allocation)
|
||||
{
|
||||
if (Node!.Allocations.Any(x => x.Port == allocation.Port && x.IpAddress == allocation.IpAddress))
|
||||
throw new DisplayException("A allocation with these ip and port does already exist");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task ValidateUpdate(ServerAllocation allocation)
|
||||
{
|
||||
if (Node!.Allocations.Any(x => x.Port == allocation.Port && x.IpAddress == allocation.IpAddress && x.Id != allocation.Id))
|
||||
throw new DisplayException("A allocation with these ip and port does already exist");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task ValidateDelete(ServerAllocation allocation)
|
||||
{
|
||||
if (ServerRepository
|
||||
.Get()
|
||||
.Any(x => x.Allocations.Any(y => y.Id == allocation.Id)))
|
||||
{
|
||||
throw new DisplayException("A server is using this allocation. Delete the server in order to delete this allocation");
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task DeleteAllAllocations()
|
||||
{
|
||||
if (!await AlertService.YesNo("Do you really want to delete all allocations?", "Yes", "No"))
|
||||
return;
|
||||
|
||||
foreach (var allocation in Node!.Allocations.ToArray()) // To array in order to prevent collection modified exception
|
||||
{
|
||||
if (ServerRepository
|
||||
.Get()
|
||||
.Any(x => x.Allocations.Any(y => y.Id == allocation.Id)))
|
||||
{
|
||||
await ToastService.Danger($"Unable to delete allocation with port {allocation.Port} due to a server using this allocation");
|
||||
continue;
|
||||
}
|
||||
|
||||
AllocationRepository.Delete(allocation);
|
||||
}
|
||||
|
||||
await ToastService.Success("Successfully deleted allocations");
|
||||
await LazyLoader.Reload();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue