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))
|
if (string.IsNullOrEmpty(Token))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!await JwtService.Validate(Token))
|
if (!await JwtService.Validate(Token, "User"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var data = await JwtService.Decode(Token);
|
var data = await JwtService.Decode(Token);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using JWT.Algorithms;
|
using JWT.Algorithms;
|
||||||
using JWT.Builder;
|
using JWT.Builder;
|
||||||
|
using JWT.Exceptions;
|
||||||
using MoonCore.Attributes;
|
using MoonCore.Attributes;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCore.Services;
|
using MoonCore.Services;
|
||||||
|
@ -43,6 +44,14 @@ public class JwtService
|
||||||
{
|
{
|
||||||
try
|
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()
|
var headerJson = new JwtBuilder()
|
||||||
.WithSecret(ConfigService.Get().Security.Token)
|
.WithSecret(ConfigService.Get().Security.Token)
|
||||||
.WithAlgorithm(new HMACSHA512Algorithm())
|
.WithAlgorithm(new HMACSHA512Algorithm())
|
||||||
|
@ -51,28 +60,34 @@ public class JwtService
|
||||||
|
|
||||||
if (headerJson == null)
|
if (headerJson == null)
|
||||||
return Task.FromResult(false);
|
return Task.FromResult(false);
|
||||||
|
|
||||||
// Jwt type validation
|
// Jwt type validation
|
||||||
if(allowedJwtTypes.Length == 0)
|
if (allowedJwtTypes.Length == 0)
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
|
|
||||||
var headerData = JsonConvert.DeserializeObject<Dictionary<string, string>>(headerJson);
|
var headerData = JsonConvert.DeserializeObject<Dictionary<string, string>>(headerJson);
|
||||||
|
|
||||||
if(headerData == null) // => Invalid header
|
if (headerData == null) // => Invalid header
|
||||||
return Task.FromResult(false);
|
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);
|
return Task.FromResult(false);
|
||||||
|
|
||||||
foreach (var name in allowedJwtTypes)
|
foreach (var name in allowedJwtTypes)
|
||||||
{
|
{
|
||||||
if(headerData["Type"] == name) // => Correct type found
|
if (headerData["Type"] == name) // => Correct type found
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// None found? Invalid type!
|
// None found? Invalid type!
|
||||||
return Task.FromResult(false);
|
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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn(e.Message);
|
Logger.Warn(e.Message);
|
||||||
|
@ -91,11 +106,17 @@ public class JwtService
|
||||||
.Decode(token);
|
.Decode(token);
|
||||||
|
|
||||||
var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
|
var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
|
||||||
|
|
||||||
return Task.FromResult(data)!;
|
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!);
|
return Task.FromResult<Dictionary<string, string>>(null!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
Sign In
|
Sign In
|
||||||
</h1>
|
</h1>
|
||||||
<div class="text-gray-400 fw-semibold fs-6">
|
<div class="text-gray-400 fw-semibold fs-6">
|
||||||
Get unlimited access & earn money
|
Change me
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
Sign Up
|
Sign Up
|
||||||
</h1>
|
</h1>
|
||||||
<div class="text-gray-400 fw-semibold fs-6">
|
<div class="text-gray-400 fw-semibold fs-6">
|
||||||
Get unlimited access & earn money
|
change me
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Net.Sockets;
|
||||||
using MoonCore.Abstractions;
|
using MoonCore.Abstractions;
|
||||||
using MoonCore.Attributes;
|
using MoonCore.Attributes;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
@ -32,6 +33,16 @@ public class InitBackgroundService : BackgroundService
|
||||||
{
|
{
|
||||||
await nodeService.Boot(node);
|
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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"An error occured while booting node '{node.Name}'");
|
Logger.Warn($"An error occured while booting node '{node.Name}'");
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.Features.Servers.Models.Forms.Admin;
|
namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes;
|
||||||
|
|
||||||
public class CreateNodeForm
|
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;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.Features.Servers.Models.Forms.Admin;
|
namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes;
|
||||||
|
|
||||||
public class UpdateNodeForm
|
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.Abstractions
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
|
@using Moonlight.Features.Servers.Models.Forms.Admin.Nodes
|
||||||
|
|
||||||
@attribute [RequirePermission(Permission.AdminServers)]
|
@attribute [RequirePermission(Permission.AdminServers)]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,166 @@
|
||||||
@page "/admin/servers/nodes/{Id:int}"
|
@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
|
@code
|
||||||
{
|
{
|
||||||
[Parameter]
|
[Parameter] public int Id { get; set; }
|
||||||
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