Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to new MoonCore version #434

Merged
merged 18 commits into from
Jul 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Moonlight/Core/Configuration/CoreConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ public class AuthenticationData
[JsonProperty("DenyRegister")]
[Description("This disables the register function. No user will be able to sign up anymore. Its recommended to enable this for private instances")]
public bool DenyRegister { get; set; } = false;

[JsonProperty("EnablePeriodicReAuth")]
[Description(
"If this option is enabled, every session will reauthenticate perdiodicly to track state changes in real time without the user refreshing the page")]
public bool EnablePeriodicReAuth { get; set; } = true;

[JsonProperty("PeriodicReAuthDelay")]
[Description(
"This option specifies how long the intervals are between reauthentications. The value is specified in minutes")]
public int PeriodicReAuthDelay { get; set; } = 5;
}

public class SecurityData
Expand Down
47 changes: 24 additions & 23 deletions Moonlight/Core/CoreFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
using MoonCore.Abstractions;
using MoonCore.Helpers;
using MoonCore.Services;
using MoonCoreUI.Extensions;
using MoonCoreUI.Services;
using Moonlight.Core.Configuration;
using Moonlight.Core.Database;
using Moonlight.Core.Database.Entities;
using Moonlight.Core.Implementations.Diagnose;
using Moonlight.Core.Implementations.UI.Admin.AdminColumns;
using Moonlight.Core.Implementations.UI.Index;
using Moonlight.Core.Interfaces;
using Moonlight.Core.Interfaces.Ui.Admin;
using Moonlight.Core.Interfaces.UI.User;
Expand All @@ -21,10 +17,16 @@
using Moonlight.Core.Repositories;
using Moonlight.Core.Services;
using Microsoft.OpenApi.Models;
using MoonCore.Blazor.Extensions;
using MoonCore.Blazor.Services;
using MoonCore.Extensions;
using Moonlight.Core.Attributes;
using Moonlight.Core.Http.Middleware;
using Moonlight.Core.Implementations.AdminDashboard;
using Moonlight.Core.Implementations.ApiDefinition;
using Moonlight.Core.Implementations.UserDashboard;
using Swashbuckle.AspNetCore.SwaggerGen;
using AuthenticationStateProvider = Moonlight.Core.Helpers.AuthenticationStateProvider;
using Microsoft.AspNetCore.Http.Features;

namespace Moonlight.Core;
Expand Down Expand Up @@ -55,25 +57,24 @@ public override Task OnPreInitialized(PreInitContext context)
builder.Services.AddDbContext<DataContext>();

//
builder.Services.AddSingleton(new JwtService<CoreJwtType>(config.Security.Token));
builder.Services.AddSingleton(new JwtService<CoreJwtType>(
config.Security.Token,
context.LoggerFactory.CreateLogger<JwtService<CoreJwtType>>()
)
);

// Mooncore services
builder.Services.AddScoped(typeof(Repository<>), typeof(GenericRepository<>));
builder.Services.AddScoped<CookieService>();
builder.Services.AddScoped<FileDownloadService>();
builder.Services.AddScoped<AlertService>();
builder.Services.AddScoped<ToastService>();
builder.Services.AddScoped<ClipboardService>();
builder.Services.AddScoped<ModalService>();

builder.Services.AddMoonCoreUi(configuration =>

builder.Services.AddMoonCore(configuration =>
{
configuration.ToastJavascriptPrefix = "moonlight.toasts";
configuration.ModalJavascriptPrefix = "moonlight.modals";
configuration.AlertJavascriptPrefix = "moonlight.alerts";
configuration.ClipboardJavascriptPrefix = "moonlight.clipboard";
configuration.FileDownloadJavascriptPrefix = "moonlight.utils";
configuration.Identity.Token = config.Security.Token;
configuration.Identity.PeriodicReAuthDelay = TimeSpan.FromMinutes(config.Authentication.PeriodicReAuthDelay);
configuration.Identity.EnablePeriodicReAuth = config.Authentication.EnablePeriodicReAuth;
configuration.Identity.Provider = new AuthenticationStateProvider();
});

builder.Services.AddMoonCoreBlazor();

// Add external services and blazor/asp.net stuff
builder.Services.AddRazorPages();
Expand Down Expand Up @@ -191,7 +192,7 @@ public override async Task OnInitialized(InitContext context)
Name = "Manage admin api access",
Description = "Allows access to manage api keys and their permissions"
});

await permissionService.Register(9999, new()
{
Name = "Manage system",
Expand Down Expand Up @@ -226,9 +227,9 @@ await startupJobService.AddJob("Default user creation", TimeSpan.FromSeconds(3),
{
using var scope = provider.CreateScope();

var configService = scope.ServiceProvider.GetRequiredService<ConfigService<CoreConfiguration>>();
var userRepo = scope.ServiceProvider.GetRequiredService<Repository<User>>();
var authenticationProvider = scope.ServiceProvider.GetRequiredService<IAuthenticationProvider>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<CoreFeature>>();

if (!configService.Get().Authentication.UseDefaultAuthentication)
return;
Expand All @@ -246,7 +247,7 @@ await startupJobService.AddJob("Default user creation", TimeSpan.FromSeconds(3),

if (registeredUser == null)
{
Logger.Warn("Unable to create default user. Register function returned null");
logger.LogWarning("Unable to create default user. Register function returned null");
return;
}

Expand All @@ -255,15 +256,15 @@ await startupJobService.AddJob("Default user creation", TimeSpan.FromSeconds(3),
user.Permissions = 9999;
userRepo.Update(user);

Logger.Info($"Default login: Email: '{email}' Password: '{password}'");
logger.LogInformation("Default login: Email: '{email}' Password: '{password}'", email, password);
});

// Api
if (config.Development.EnableApiReference)
app.MapSwagger("/api/core/reference/openapi/{documentName}");

app.UseMiddleware<ApiPermissionMiddleware>();

await pluginService.RegisterImplementation<IApiDefinition>(new InternalApiDefinition());
}

Expand Down
5 changes: 5 additions & 0 deletions Moonlight/Core/Database/DataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,9 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
);
}
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{

}
}
11 changes: 9 additions & 2 deletions Moonlight/Core/Events/CoreEvents.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
using MoonCore.Helpers;
using MoonCore.Attributes;
using MoonCore.Helpers;

namespace Moonlight.Core.Events;

[Singleton]
public class CoreEvents
{
public static SmartEventHandler OnMoonlightRestart { get; set; } = new();
public CoreEvents(ILogger<SmartEventHandler> logger)
{
OnMoonlightRestart = new(logger);
}

public SmartEventHandler OnMoonlightRestart { get; set; }
}
54 changes: 54 additions & 0 deletions Moonlight/Core/Extensions/IdentityServiceExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using MoonCore.Abstractions;
using MoonCore.Services;
using Moonlight.Core.Database.Entities;

namespace Moonlight.Core.Extensions;

public static class IdentityServiceExtensions
{
public static User GetUser(this IdentityService identityService)
{
return identityService.Storage.Get<User>();
}

public static Task<bool> HasFlag(this IdentityService identityService, string flag)
{
if (!identityService.IsAuthenticated)
return Task.FromResult(false);

var result = identityService.GetUser().Flags.Split(";").Contains(flag);
return Task.FromResult(result);
}

public static Task SetFlag(this IdentityService identityService, string flag, bool toggle)
{
if (!identityService.IsAuthenticated)
return Task.CompletedTask;

var user = identityService.GetUser();

// Rebuild flags
var flags = user.Flags.Split(";").ToList();

if (toggle)
{
if(!flags.Contains(flag))
flags.Add(flag);
}
else
{
if (flags.Contains(flag))
flags.Remove(flag);
}

user.Flags = string.Join(';', flags);

// Save changes
var serviceProvider = identityService.Storage.Get<IServiceProvider>();
var userRepo = serviceProvider.GetRequiredService<Repository<User>>();

userRepo.Update(user);

return Task.CompletedTask;
}
}
50 changes: 50 additions & 0 deletions Moonlight/Core/Helpers/AuthenticationStateProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using MoonCore.Abstractions;
using MoonCore.Helpers;
using Moonlight.Core.Database.Entities;

namespace Moonlight.Core.Helpers;

public class AuthenticationStateProvider : MoonCore.Abstractions.AuthenticationStateProvider
{
public override Task<bool> IsValidIdentifier(IServiceProvider provider, string identifier)
{
if(!int.TryParse(identifier, out int searchId))
return Task.FromResult(false);

var userRepo = provider.GetRequiredService<Repository<User>>();
var result = userRepo.Get().Any(x => x.Id == searchId);

return Task.FromResult(result);
}

public override Task LoadFromIdentifier(IServiceProvider provider, string identifier, DynamicStorage storage)
{
if(!int.TryParse(identifier, out int searchId))
return Task.CompletedTask;

var userRepo = provider.GetRequiredService<Repository<User>>();
var user = userRepo.Get().FirstOrDefault(x => x.Id == searchId);

if(user == null)
return Task.CompletedTask;

storage.Set("User", user);
storage.Set("ServiceProvider", provider);

return Task.CompletedTask;
}

public override Task<DateTime> DetermineTokenValidTimestamp(IServiceProvider provider, string identifier)
{
if(!int.TryParse(identifier, out int searchId))
return Task.FromResult(DateTime.MaxValue);

var userRepo = provider.GetRequiredService<Repository<User>>();
var user = userRepo.Get().FirstOrDefault(x => x.Id == searchId);

if(user == null)
return Task.FromResult(DateTime.MaxValue);

return Task.FromResult(user.TokenValidTimestamp);
}
}
20 changes: 14 additions & 6 deletions Moonlight/Core/Helpers/HostSystemHelper.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using MoonCore.Attributes;
using MoonCore.Helpers;

namespace Moonlight.Core.Helpers;

public static class HostSystemHelper
[Singleton]
public class HostSystemHelper
{
public static Task<string> GetOsName()
private readonly ILogger<HostSystemHelper> Logger;

public HostSystemHelper(ILogger<HostSystemHelper> logger)
{
Logger = logger;
}

public Task<string> GetOsName()
{
try
{
Expand Down Expand Up @@ -48,21 +57,20 @@ public static Task<string> GetOsName()
}
catch (Exception e)
{
Logger.Warn("Error retrieving os information");
Logger.Warn(e);
Logger.LogWarning("Error retrieving os information: {e}", e);

return Task.FromResult("N/A");
}
}

public static Task<long> GetMemoryUsage()
public Task<long> GetMemoryUsage()
{
var process = Process.GetCurrentProcess();
var bytes = process.PrivateMemorySize64;
return Task.FromResult(bytes);
}

public static Task<int> GetCpuUsage()
public Task<int> GetCpuUsage()
{
var process = Process.GetCurrentProcess();
var cpuTime = process.TotalProcessorTime;
Expand Down
9 changes: 8 additions & 1 deletion Moonlight/Core/Http/Controllers/AssetController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@ namespace Moonlight.Core.Http.Controllers;
[Route("api/core/asset")]
public class AssetController : Controller
{
private readonly ILogger<AssetController> Logger;

public AssetController(ILogger<AssetController> logger)
{
Logger = logger;
}

[HttpGet("{name}/{*path}")]
public async Task<ActionResult> Get(string name, string path)
{
// Check for path transversal attacks
if (path.Contains("..") || name.Contains(".."))
{
Logger.Warn($"{HttpContext.Connection.RemoteIpAddress} tried to use path transversal attack: {name}/{path}");
Logger.LogWarning("{remoteIp} tried to use path transversal attack: {name}/{path}", HttpContext.Connection.RemoteIpAddress, name, path);
return NotFound();
}

Expand Down
Loading
Loading