Fixed jwt validation error. Added node allocations editor. Small fixes

This commit is contained in:
Marcel Baumgartner 2024-02-07 21:08:37 +01:00
parent 70445069fd
commit 1b427607d1
11 changed files with 235 additions and 19 deletions

View file

@ -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);

View file

@ -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!);
}
}

View file

@ -16,7 +16,7 @@
Sign In
</h1>
<div class="text-gray-400 fw-semibold fs-6">
Get unlimited access &amp; earn money
Change me
</div>
</div>

View file

@ -19,7 +19,7 @@
Sign Up
</h1>
<div class="text-gray-400 fw-semibold fs-6">
Get unlimited access &amp; earn money
change me
</div>
</div>

View file

@ -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}'");

View file

@ -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
{

View file

@ -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; }
}

View file

@ -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
{

View file

@ -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; }
}

View file

@ -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)]

View file

@ -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();
}
}