diff --git a/MoonlightServers.ApiServer/Http/Controllers/Users/ServerPowerController.cs b/MoonlightServers.ApiServer/Http/Controllers/Users/ServerPowerController.cs index 43fe3f6..921f5e3 100644 --- a/MoonlightServers.ApiServer/Http/Controllers/Users/ServerPowerController.cs +++ b/MoonlightServers.ApiServer/Http/Controllers/Users/ServerPowerController.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using MoonCore.Exceptions; using MoonCore.Extended.Abstractions; using MoonCore.Extensions; +using MoonCore.Helpers; using MoonlightServers.ApiServer.Database.Entities; using MoonlightServers.ApiServer.Services; @@ -117,7 +118,9 @@ public class ServerPowerController : Controller if (server.OwnerId == userId) // The current user is the owner return server; - if (User.HasPermission("admin.servers.get")) // The current user is an admin + var permissions = User.Claims.First(x => x.Type == "permissions").Value.Split(";", StringSplitOptions.RemoveEmptyEntries); + + if (PermissionHelper.HasPermission(permissions, "admin.servers.get")) // The current user is an admin return server; throw new HttpApiException("No server with this id found", 404); diff --git a/MoonlightServers.ApiServer/Http/Controllers/Users/ServersController.cs b/MoonlightServers.ApiServer/Http/Controllers/Users/ServersController.cs index 539e4a5..98008d4 100644 --- a/MoonlightServers.ApiServer/Http/Controllers/Users/ServersController.cs +++ b/MoonlightServers.ApiServer/Http/Controllers/Users/ServersController.cs @@ -5,6 +5,7 @@ using MoonCore.Extended.PermFilter; using MoonCore.Exceptions; using MoonCore.Extended.Abstractions; using MoonCore.Extensions; +using MoonCore.Helpers; using MoonCore.Models; using Moonlight.ApiServer.Database.Entities; using MoonlightServers.ApiServer.Database.Entities; @@ -198,7 +199,9 @@ public class ServersController : Controller if (server.OwnerId == userId) // The current user is the owner return server; - if (User.HasPermission("admin.servers.get")) // The current user is an admin + var permissions = User.Claims.First(x => x.Type == "permissions").Value.Split(";", StringSplitOptions.RemoveEmptyEntries); + + if (PermissionHelper.HasPermission(permissions, "admin.servers.get")) // The current user is an admin return server; throw new HttpApiException("No server with this id found", 404); diff --git a/MoonlightServers.ApiServer/Services/NodeService.cs b/MoonlightServers.ApiServer/Services/NodeService.cs index efa8fc9..cefe66e 100644 --- a/MoonlightServers.ApiServer/Services/NodeService.cs +++ b/MoonlightServers.ApiServer/Services/NodeService.cs @@ -1,3 +1,7 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using Microsoft.IdentityModel.Tokens; using MoonCore.Attributes; using MoonCore.Extended.Helpers; using MoonCore.Helpers; @@ -20,20 +24,43 @@ public class NodeService url += "http://"; url += $"{node.Fqdn}:{node.HttpPort}/"; - + var httpClient = new HttpClient() { BaseAddress = new Uri(url) }; - + httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {node.Token}"); return new HttpApiClient(httpClient); } public string CreateAccessToken(Node node, Action> parameters, TimeSpan duration) - => JwtHelper.Encode(node.Token, parameters, duration); - + { + var claims = new Dictionary(); + parameters.Invoke(claims); + + var jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); + + var securityTokenDescriptor = new SecurityTokenDescriptor() + { + Expires = DateTime.UtcNow.Add(duration), + NotBefore = DateTime.UtcNow.AddSeconds(-1), + Claims = claims, + IssuedAt = DateTime.UtcNow, + SigningCredentials = new SigningCredentials( + new SymmetricSecurityKey(Encoding.UTF8.GetBytes( + node.Token + )), + SecurityAlgorithms.HmacSha256 + ) + }; + + var securityToken = jwtSecurityTokenHandler.CreateJwtSecurityToken(securityTokenDescriptor); + + return jwtSecurityTokenHandler.WriteToken(securityToken); + } + public async Task GetSystemStatus(Node node) { using var apiClient = await CreateApiClient(node); @@ -47,13 +74,13 @@ public class NodeService using var apiClient = await CreateApiClient(node); return await apiClient.GetJson("api/statistics/application"); } - + public async Task GetHostStatistics(Node node) { using var apiClient = await CreateApiClient(node); return await apiClient.GetJson("api/statistics/host"); } - + public async Task GetDockerStatistics(Node node) { using var apiClient = await CreateApiClient(node); diff --git a/MoonlightServers.ApiServer/Startup/DatabaseStartup.cs b/MoonlightServers.ApiServer/Startup/DatabaseStartup.cs deleted file mode 100644 index 75f8e80..0000000 --- a/MoonlightServers.ApiServer/Startup/DatabaseStartup.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Moonlight.ApiServer.Helpers; -using Moonlight.ApiServer.Interfaces.Startup; -using MoonlightServers.ApiServer.Database; - -namespace MoonlightServers.ApiServer.Startup; - -public class DatabaseStartup : IDatabaseStartup -{ - public Task ConfigureDatabase(DatabaseContextCollection collection) - { - collection.Add(); - - return Task.CompletedTask; - } -} \ No newline at end of file diff --git a/MoonlightServers.ApiServer/Startup/PluginStartup.cs b/MoonlightServers.ApiServer/Startup/PluginStartup.cs index 6680191..1e19dfc 100644 --- a/MoonlightServers.ApiServer/Startup/PluginStartup.cs +++ b/MoonlightServers.ApiServer/Startup/PluginStartup.cs @@ -1,10 +1,12 @@ using MoonCore.Extensions; +using Moonlight.ApiServer.Helpers; using Moonlight.ApiServer.Interfaces.Startup; using Moonlight.ApiServer.Services; +using MoonlightServers.ApiServer.Database; namespace MoonlightServers.ApiServer.Startup; -public class PluginStartup : IAppStartup +public class PluginStartup : IPluginStartup { private readonly BundleService BundleService; @@ -13,19 +15,27 @@ public class PluginStartup : IAppStartup BundleService = bundleService; } - public Task BuildApp(IHostApplicationBuilder builder) + public Task BuildApplication(IHostApplicationBuilder builder) { // Scan the current plugin assembly for di services builder.Services.AutoAddServices(); BundleService.BundleCss("css/MoonlightServers.min.css"); BundleService.BundleCss("css/XtermBlazor.min.css"); - + return Task.CompletedTask; } - public Task ConfigureApp(IApplicationBuilder app) + public Task ConfigureApplication(IApplicationBuilder app) + => Task.CompletedTask; + + public Task ConfigureDatabase(DatabaseContextCollection collection) { + collection.Add(); + return Task.CompletedTask; } + + public Task ConfigureEndpoints(IEndpointRouteBuilder routeBuilder) + => Task.CompletedTask; } \ No newline at end of file diff --git a/MoonlightServers.Daemon/Abstractions/Server.Crash.cs b/MoonlightServers.Daemon/Abstractions/Server.Crash.cs index aa830dd..9d1cc8c 100644 --- a/MoonlightServers.Daemon/Abstractions/Server.Crash.cs +++ b/MoonlightServers.Daemon/Abstractions/Server.Crash.cs @@ -35,7 +35,7 @@ public partial class Server public async Task InternalError() { await LogToConsole("An unhandled error occured performing action"); - + // TODO: Logger.LogInformation("Reporting or smth"); } } \ No newline at end of file diff --git a/MoonlightServers.Daemon/Helpers/AccessTokenHelper.cs b/MoonlightServers.Daemon/Helpers/AccessTokenHelper.cs index 32380d9..bb28c52 100644 --- a/MoonlightServers.Daemon/Helpers/AccessTokenHelper.cs +++ b/MoonlightServers.Daemon/Helpers/AccessTokenHelper.cs @@ -1,4 +1,8 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; using System.Text.Json; +using Microsoft.IdentityModel.Tokens; using MoonCore.Attributes; using MoonCore.Extended.Helpers; using MoonlightServers.Daemon.Configuration; @@ -15,8 +19,33 @@ public class AccessTokenHelper Configuration = configuration; } - public bool Process(string accessToken, out Dictionary data) +// TODO: Improve + public bool Process(string accessToken, out Claim[] claims) { - return JwtHelper.TryVerifyAndDecodePayload(Configuration.Security.Token, accessToken, out data); + var jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); + + try + { + var data = jwtSecurityTokenHandler.ValidateToken(accessToken, new() + { + ClockSkew = TimeSpan.Zero, + ValidateLifetime = true, + ValidateAudience = false, + ValidateIssuer = false, + ValidateActor = false, + IssuerSigningKey = new SymmetricSecurityKey( + Encoding.UTF8.GetBytes(Configuration.Security.Token) + ) + }, out var _); + + claims = data.Claims.ToArray(); + + return true; + } + catch (Exception e) + { + claims = []; + return false; + } } } \ No newline at end of file diff --git a/MoonlightServers.Daemon/Helpers/ServerWebSocketConnection.cs b/MoonlightServers.Daemon/Helpers/ServerWebSocketConnection.cs index 08900d7..470b0e8 100644 --- a/MoonlightServers.Daemon/Helpers/ServerWebSocketConnection.cs +++ b/MoonlightServers.Daemon/Helpers/ServerWebSocketConnection.cs @@ -50,7 +50,7 @@ public class ServerWebSocketConnection } // Validate access token data - if (!accessData.ContainsKey("type") || !accessData.ContainsKey("serverId")) + if (accessData.All(x => x.Type != "type") || accessData.All(x => x.Type != "serverId")) { Logger.LogDebug("Received invalid access token: Required parameters are missing"); @@ -63,7 +63,7 @@ public class ServerWebSocketConnection } // Validate access token type - var type = accessData["type"].GetString()!; + var type = accessData.First(x => x.Type == "type").Value; if (type != "websocket") { @@ -77,7 +77,7 @@ public class ServerWebSocketConnection return; } - var serverId = accessData["serverId"].GetInt32(); + var serverId = int.Parse(accessData.First(x => x.Type == "serverId").Value); // Check that the access token isn't for another server if (ServerId != -1 && ServerId == serverId) diff --git a/MoonlightServers.Daemon/MoonlightServers.Daemon.csproj b/MoonlightServers.Daemon/MoonlightServers.Daemon.csproj index 5fbb39f..7261d5b 100644 --- a/MoonlightServers.Daemon/MoonlightServers.Daemon.csproj +++ b/MoonlightServers.Daemon/MoonlightServers.Daemon.csproj @@ -9,9 +9,9 @@ - - - + + + diff --git a/MoonlightServers.Frontend/Startup/PluginStartup.cs b/MoonlightServers.Frontend/Startup/PluginStartup.cs index 2bb75f2..4b88831 100644 --- a/MoonlightServers.Frontend/Startup/PluginStartup.cs +++ b/MoonlightServers.Frontend/Startup/PluginStartup.cs @@ -1,28 +1,24 @@ using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MoonCore.Extensions; -using MoonCore.PluginFramework.Extensions; using Moonlight.Client.Interfaces; +using MoonlightServers.Frontend.Implementations; using MoonlightServers.Frontend.Interfaces; namespace MoonlightServers.Frontend.Startup; -public class PluginStartup : IAppStartup +public class PluginStartup : IPluginStartup { - public Task BuildApp(WebAssemblyHostBuilder builder) + public Task BuildApplication(WebAssemblyHostBuilder builder) { + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AutoAddServices(); - - builder.Services.AddInterfaces(configuration => - { - configuration.AddAssembly(GetType().Assembly); - - configuration.AddInterface(); - }); return Task.CompletedTask; } - public Task ConfigureApp(WebAssemblyHost app) + public Task ConfigureApplication(WebAssemblyHost app) { return Task.CompletedTask; } diff --git a/MoonlightServers.Frontend/UI/Views/User/Manage.razor b/MoonlightServers.Frontend/UI/Views/User/Manage.razor index aa171fe..a098d4e 100644 --- a/MoonlightServers.Frontend/UI/Views/User/Manage.razor +++ b/MoonlightServers.Frontend/UI/Views/User/Manage.razor @@ -12,7 +12,7 @@ @using MoonlightServers.Frontend.UI.Components.Servers.ServerTabs @inject HttpApiClient ApiClient -@inject IServerTabProvider[] TabProviders +@inject IEnumerable TabProviders @implements IAsyncDisposable