diff --git a/Moonlight/App/Database/Entities/LogsEntries/AuditLogEntry.cs b/Moonlight/App/Database/Entities/LogsEntries/AuditLogEntry.cs index 3036caf..5b6f808 100644 --- a/Moonlight/App/Database/Entities/LogsEntries/AuditLogEntry.cs +++ b/Moonlight/App/Database/Entities/LogsEntries/AuditLogEntry.cs @@ -9,4 +9,5 @@ public class AuditLogEntry public string JsonData { get; set; } = ""; public bool System { get; set; } public string Ip { get; set; } = ""; + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; } \ No newline at end of file diff --git a/Moonlight/App/Database/Entities/LogsEntries/ErrorLogEntry.cs b/Moonlight/App/Database/Entities/LogsEntries/ErrorLogEntry.cs index 7fd09d5..ea9b7ee 100644 --- a/Moonlight/App/Database/Entities/LogsEntries/ErrorLogEntry.cs +++ b/Moonlight/App/Database/Entities/LogsEntries/ErrorLogEntry.cs @@ -8,4 +8,5 @@ public class ErrorLogEntry public string JsonData { get; set; } = ""; public string Ip { get; set; } = ""; public string Class { get; set; } = ""; + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; } \ No newline at end of file diff --git a/Moonlight/App/Database/Entities/LogsEntries/SecurityLogEntry.cs b/Moonlight/App/Database/Entities/LogsEntries/SecurityLogEntry.cs index b8efd45..9d1750b 100644 --- a/Moonlight/App/Database/Entities/LogsEntries/SecurityLogEntry.cs +++ b/Moonlight/App/Database/Entities/LogsEntries/SecurityLogEntry.cs @@ -9,4 +9,5 @@ public class SecurityLogEntry public string Ip { get; set; } = ""; public SecurityLogType Type { get; set; } public string JsonData { get; set; } = ""; + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; } \ No newline at end of file diff --git a/Moonlight/App/Database/Migrations/20230305014834_AddedLoggingAndDbStuff.Designer.cs b/Moonlight/App/Database/Migrations/20230305014834_AddedLoggingAndDbStuff.Designer.cs new file mode 100644 index 0000000..c30818e --- /dev/null +++ b/Moonlight/App/Database/Migrations/20230305014834_AddedLoggingAndDbStuff.Designer.cs @@ -0,0 +1,925 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Moonlight.App.Database; + +#nullable disable + +namespace Moonlight.App.Database.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20230305014834_AddedLoggingAndDbStuff")] + partial class AddedLoggingAndDbStuff + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AaPanelId") + .HasColumnType("int"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Databases"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Default") + .HasColumnType("tinyint(1)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("DockerImages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("SharedDomainId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.HasIndex("SharedDomainId"); + + b.ToTable("Domains"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigFiles") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallDockerImage") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallEntrypoint") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallScript") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Startup") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StartupDetection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StopCommand") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Images"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("ImageTags"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("ImageVariables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LoadingMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("LoadingMessages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.AuditLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AuditLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.ErrorLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Class") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Stacktrace") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("ErrorLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.SecurityLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("SecurityLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Fqdn") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("HttpPort") + .HasColumnType("int"); + + b.Property("MoonlightDaemonPort") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SftpPort") + .HasColumnType("int"); + + b.Property("Ssl") + .HasColumnType("tinyint(1)"); + + b.Property("Token") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TokenId") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Nodes"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NodeId"); + + b.HasIndex("ServerId"); + + b.ToTable("NodeAllocations"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NotificationClientId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NotificationClientId"); + + b.ToTable("NotificationActions"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("NotificationClients"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Revoke", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Identifier") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Revokes"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Cpu") + .HasColumnType("int"); + + b.Property("Disk") + .HasColumnType("bigint"); + + b.Property("DockerImageIndex") + .HasColumnType("int"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Installing") + .HasColumnType("tinyint(1)"); + + b.Property("MainAllocationId") + .HasColumnType("int"); + + b.Property("Memory") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("OverrideStartup") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("Suspended") + .HasColumnType("tinyint(1)"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("MainAllocationId"); + + b.HasIndex("NodeId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Servers"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Bytes") + .HasColumnType("bigint"); + + b.Property("Created") + .HasColumnType("tinyint(1)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.ToTable("ServerBackups"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.ToTable("ServerVariables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SharedDomain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CloudflareId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SharedDomains"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Subscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SellPassId") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Subscriptions"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SubscriptionLimit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("int"); + + b.Property("Cpu") + .HasColumnType("int"); + + b.Property("Disk") + .HasColumnType("int"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Memory") + .HasColumnType("int"); + + b.Property("SubscriptionId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("SubscriptionId"); + + b.ToTable("SubscriptionLimits"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Answer") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsQuestion") + .HasColumnType("tinyint(1)"); + + b.Property("IsSupport") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RecipientId") + .HasColumnType("int"); + + b.Property("SenderId") + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("RecipientId"); + + b.HasIndex("SenderId"); + + b.ToTable("SupportMessages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Address") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Admin") + .HasColumnType("tinyint(1)"); + + b.Property("City") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Country") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("DiscordDiscriminator") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DiscordId") + .HasColumnType("bigint"); + + b.Property("DiscordUsername") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Email") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("State") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SubscriptionDuration") + .HasColumnType("int"); + + b.Property("SubscriptionId") + .HasColumnType("int"); + + b.Property("SubscriptionSince") + .HasColumnType("datetime(6)"); + + b.Property("SupportPending") + .HasColumnType("tinyint(1)"); + + b.Property("TokenValidTime") + .HasColumnType("datetime(6)"); + + b.Property("TotpEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("TotpSecret") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("SubscriptionId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", null) + .WithMany("DockerImages") + .HasForeignKey("ImageId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Domain", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.SharedDomain", "SharedDomain") + .WithMany() + .HasForeignKey("SharedDomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + + b.Navigation("SharedDomain"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", null) + .WithMany("Tags") + .HasForeignKey("ImageId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", null) + .WithMany("Variables") + .HasForeignKey("ImageId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b => + { + b.HasOne("Moonlight.App.Database.Entities.Node", null) + .WithMany("Allocations") + .HasForeignKey("NodeId"); + + b.HasOne("Moonlight.App.Database.Entities.Server", null) + .WithMany("Allocations") + .HasForeignKey("ServerId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationAction", b => + { + b.HasOne("Moonlight.App.Database.Entities.Notification.NotificationClient", "NotificationClient") + .WithMany() + .HasForeignKey("NotificationClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NotificationClient"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationClient", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", "Image") + .WithMany() + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.NodeAllocation", "MainAllocation") + .WithMany() + .HasForeignKey("MainAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.Node", "Node") + .WithMany() + .HasForeignKey("NodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + + b.Navigation("MainAllocation"); + + b.Navigation("Node"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b => + { + b.HasOne("Moonlight.App.Database.Entities.Server", null) + .WithMany("Backups") + .HasForeignKey("ServerId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b => + { + b.HasOne("Moonlight.App.Database.Entities.Server", null) + .WithMany("Variables") + .HasForeignKey("ServerId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SubscriptionLimit", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", "Image") + .WithMany() + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.Subscription", null) + .WithMany("Limits") + .HasForeignKey("SubscriptionId"); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "Recipient") + .WithMany() + .HasForeignKey("RecipientId"); + + b.HasOne("Moonlight.App.Database.Entities.User", "Sender") + .WithMany() + .HasForeignKey("SenderId"); + + b.Navigation("Recipient"); + + b.Navigation("Sender"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.User", b => + { + b.HasOne("Moonlight.App.Database.Entities.Subscription", "Subscription") + .WithMany() + .HasForeignKey("SubscriptionId"); + + b.Navigation("Subscription"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b => + { + b.Navigation("DockerImages"); + + b.Navigation("Tags"); + + b.Navigation("Variables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b => + { + b.Navigation("Allocations"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b => + { + b.Navigation("Allocations"); + + b.Navigation("Backups"); + + b.Navigation("Variables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Subscription", b => + { + b.Navigation("Limits"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Moonlight/App/Database/Migrations/20230305014834_AddedLoggingAndDbStuff.cs b/Moonlight/App/Database/Migrations/20230305014834_AddedLoggingAndDbStuff.cs new file mode 100644 index 0000000..c02562c --- /dev/null +++ b/Moonlight/App/Database/Migrations/20230305014834_AddedLoggingAndDbStuff.cs @@ -0,0 +1,66 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Moonlight.App.Database.Migrations +{ + /// + public partial class AddedLoggingAndDbStuff : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ErrorLog", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Stacktrace = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + System = table.Column(type: "tinyint(1)", nullable: false), + JsonData = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Ip = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Class = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_ErrorLog", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "SecurityLog", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + System = table.Column(type: "tinyint(1)", nullable: false), + Ip = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Type = table.Column(type: "int", nullable: false), + JsonData = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_SecurityLog", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ErrorLog"); + + migrationBuilder.DropTable( + name: "SecurityLog"); + } + } +} diff --git a/Moonlight/App/Database/Migrations/20230305021844_AddedDatesToLogs.Designer.cs b/Moonlight/App/Database/Migrations/20230305021844_AddedDatesToLogs.Designer.cs new file mode 100644 index 0000000..c9b6f20 --- /dev/null +++ b/Moonlight/App/Database/Migrations/20230305021844_AddedDatesToLogs.Designer.cs @@ -0,0 +1,934 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Moonlight.App.Database; + +#nullable disable + +namespace Moonlight.App.Database.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20230305021844_AddedDatesToLogs")] + partial class AddedDatesToLogs + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AaPanelId") + .HasColumnType("int"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Databases"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Default") + .HasColumnType("tinyint(1)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("DockerImages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("SharedDomainId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.HasIndex("SharedDomainId"); + + b.ToTable("Domains"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigFiles") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallDockerImage") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallEntrypoint") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallScript") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Startup") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StartupDetection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StopCommand") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Images"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("ImageTags"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("ImageVariables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LoadingMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("LoadingMessages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.AuditLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AuditLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.ErrorLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Class") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Stacktrace") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("ErrorLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.SecurityLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("SecurityLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Fqdn") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("HttpPort") + .HasColumnType("int"); + + b.Property("MoonlightDaemonPort") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SftpPort") + .HasColumnType("int"); + + b.Property("Ssl") + .HasColumnType("tinyint(1)"); + + b.Property("Token") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TokenId") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Nodes"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NodeId"); + + b.HasIndex("ServerId"); + + b.ToTable("NodeAllocations"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NotificationClientId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NotificationClientId"); + + b.ToTable("NotificationActions"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("NotificationClients"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Revoke", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Identifier") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Revokes"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Cpu") + .HasColumnType("int"); + + b.Property("Disk") + .HasColumnType("bigint"); + + b.Property("DockerImageIndex") + .HasColumnType("int"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Installing") + .HasColumnType("tinyint(1)"); + + b.Property("MainAllocationId") + .HasColumnType("int"); + + b.Property("Memory") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("OverrideStartup") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("Suspended") + .HasColumnType("tinyint(1)"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("MainAllocationId"); + + b.HasIndex("NodeId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Servers"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Bytes") + .HasColumnType("bigint"); + + b.Property("Created") + .HasColumnType("tinyint(1)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.ToTable("ServerBackups"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.ToTable("ServerVariables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SharedDomain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CloudflareId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SharedDomains"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Subscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SellPassId") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Subscriptions"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SubscriptionLimit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("int"); + + b.Property("Cpu") + .HasColumnType("int"); + + b.Property("Disk") + .HasColumnType("int"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Memory") + .HasColumnType("int"); + + b.Property("SubscriptionId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("SubscriptionId"); + + b.ToTable("SubscriptionLimits"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Answer") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsQuestion") + .HasColumnType("tinyint(1)"); + + b.Property("IsSupport") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RecipientId") + .HasColumnType("int"); + + b.Property("SenderId") + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("RecipientId"); + + b.HasIndex("SenderId"); + + b.ToTable("SupportMessages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Address") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Admin") + .HasColumnType("tinyint(1)"); + + b.Property("City") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Country") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("DiscordDiscriminator") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DiscordId") + .HasColumnType("bigint"); + + b.Property("DiscordUsername") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Email") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("State") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SubscriptionDuration") + .HasColumnType("int"); + + b.Property("SubscriptionId") + .HasColumnType("int"); + + b.Property("SubscriptionSince") + .HasColumnType("datetime(6)"); + + b.Property("SupportPending") + .HasColumnType("tinyint(1)"); + + b.Property("TokenValidTime") + .HasColumnType("datetime(6)"); + + b.Property("TotpEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("TotpSecret") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("SubscriptionId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", null) + .WithMany("DockerImages") + .HasForeignKey("ImageId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Domain", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.SharedDomain", "SharedDomain") + .WithMany() + .HasForeignKey("SharedDomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + + b.Navigation("SharedDomain"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", null) + .WithMany("Tags") + .HasForeignKey("ImageId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", null) + .WithMany("Variables") + .HasForeignKey("ImageId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b => + { + b.HasOne("Moonlight.App.Database.Entities.Node", null) + .WithMany("Allocations") + .HasForeignKey("NodeId"); + + b.HasOne("Moonlight.App.Database.Entities.Server", null) + .WithMany("Allocations") + .HasForeignKey("ServerId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationAction", b => + { + b.HasOne("Moonlight.App.Database.Entities.Notification.NotificationClient", "NotificationClient") + .WithMany() + .HasForeignKey("NotificationClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NotificationClient"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationClient", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", "Image") + .WithMany() + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.NodeAllocation", "MainAllocation") + .WithMany() + .HasForeignKey("MainAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.Node", "Node") + .WithMany() + .HasForeignKey("NodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + + b.Navigation("MainAllocation"); + + b.Navigation("Node"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b => + { + b.HasOne("Moonlight.App.Database.Entities.Server", null) + .WithMany("Backups") + .HasForeignKey("ServerId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b => + { + b.HasOne("Moonlight.App.Database.Entities.Server", null) + .WithMany("Variables") + .HasForeignKey("ServerId"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SubscriptionLimit", b => + { + b.HasOne("Moonlight.App.Database.Entities.Image", "Image") + .WithMany() + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.Subscription", null) + .WithMany("Limits") + .HasForeignKey("SubscriptionId"); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "Recipient") + .WithMany() + .HasForeignKey("RecipientId"); + + b.HasOne("Moonlight.App.Database.Entities.User", "Sender") + .WithMany() + .HasForeignKey("SenderId"); + + b.Navigation("Recipient"); + + b.Navigation("Sender"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.User", b => + { + b.HasOne("Moonlight.App.Database.Entities.Subscription", "Subscription") + .WithMany() + .HasForeignKey("SubscriptionId"); + + b.Navigation("Subscription"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b => + { + b.Navigation("DockerImages"); + + b.Navigation("Tags"); + + b.Navigation("Variables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b => + { + b.Navigation("Allocations"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b => + { + b.Navigation("Allocations"); + + b.Navigation("Backups"); + + b.Navigation("Variables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Subscription", b => + { + b.Navigation("Limits"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Moonlight/App/Database/Migrations/20230305021844_AddedDatesToLogs.cs b/Moonlight/App/Database/Migrations/20230305021844_AddedDatesToLogs.cs new file mode 100644 index 0000000..7276d7c --- /dev/null +++ b/Moonlight/App/Database/Migrations/20230305021844_AddedDatesToLogs.cs @@ -0,0 +1,52 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Moonlight.App.Database.Migrations +{ + /// + public partial class AddedDatesToLogs : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CreatedAt", + table: "SecurityLog", + type: "datetime(6)", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "CreatedAt", + table: "ErrorLog", + type: "datetime(6)", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "CreatedAt", + table: "AuditLog", + type: "datetime(6)", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CreatedAt", + table: "SecurityLog"); + + migrationBuilder.DropColumn( + name: "CreatedAt", + table: "ErrorLog"); + + migrationBuilder.DropColumn( + name: "CreatedAt", + table: "AuditLog"); + } + } +} diff --git a/Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs b/Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs index d5119b3..335da5b 100644 --- a/Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs +++ b/Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs @@ -19,31 +19,6 @@ namespace Moonlight.App.Database.Migrations .HasAnnotation("ProductVersion", "7.0.3") .HasAnnotation("Relational:MaxIdentifierLength", 64); - modelBuilder.Entity("Moonlight.App.Database.Entities.AuditLogEntry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - b.Property("Ip") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("JsonData") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("System") - .HasColumnType("tinyint(1)"); - - b.Property("Type") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.ToTable("AuditLog"); - }); - modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b => { b.Property("Id") @@ -220,6 +195,95 @@ namespace Moonlight.App.Database.Migrations b.ToTable("LoadingMessages"); }); + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.AuditLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AuditLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.ErrorLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Class") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Stacktrace") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("ErrorLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.SecurityLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("SecurityLog"); + }); + modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b => { b.Property("Id") diff --git a/Moonlight/App/Helpers/Formatter.cs b/Moonlight/App/Helpers/Formatter.cs index 3d5e2fe..1725df9 100644 --- a/Moonlight/App/Helpers/Formatter.cs +++ b/Moonlight/App/Helpers/Formatter.cs @@ -76,4 +76,16 @@ public static class Formatter return $"{i2s(e.Day)}.{i2s(e.Month)}.{e.Year} {i2s(e.Hour)}:{i2s(e.Minute)}"; } + + public static string FormatDateOnly(DateTime e) + { + string i2s(int i) + { + if (i.ToString().Length < 2) + return "0" + i; + return i.ToString(); + } + + return $"{i2s(e.Day)}.{i2s(e.Month)}.{e.Year}"; + } } \ No newline at end of file diff --git a/Moonlight/App/Helpers/WingsServerConverter.cs b/Moonlight/App/Helpers/WingsServerConverter.cs index 2b4c33d..2ef6ef6 100644 --- a/Moonlight/App/Helpers/WingsServerConverter.cs +++ b/Moonlight/App/Helpers/WingsServerConverter.cs @@ -67,7 +67,7 @@ public class WingsServerConverter // Settings wingsServer.Settings.Skip_Egg_Scripts = false; - wingsServer.Settings.Suspended = false; //TODO: Implement + wingsServer.Settings.Suspended = server.Suspended; wingsServer.Settings.Invocation = string.IsNullOrEmpty(server.OverrideStartup) ? image.Startup : server.OverrideStartup; wingsServer.Settings.Uuid = server.Uuid; diff --git a/Moonlight/App/Http/Controllers/Api/Moonlight/Notifications/PullController.cs b/Moonlight/App/Http/Controllers/Api/Moonlight/Notifications/PullController.cs index 8a6aecd..b86add6 100644 --- a/Moonlight/App/Http/Controllers/Api/Moonlight/Notifications/PullController.cs +++ b/Moonlight/App/Http/Controllers/Api/Moonlight/Notifications/PullController.cs @@ -27,7 +27,7 @@ public class PullController : Controller Stream req = Request.Body; string jwt = await new StreamReader(req).ReadToEndAsync(); - var dict = OneTimeJwtService.Validate(jwt); + var dict = await OneTimeJwtService.Validate(jwt); if (dict == null) return NotFound(); diff --git a/Moonlight/App/Http/Controllers/Api/Moonlight/ResourcesController.cs b/Moonlight/App/Http/Controllers/Api/Moonlight/ResourcesController.cs index f093785..a02762c 100644 --- a/Moonlight/App/Http/Controllers/Api/Moonlight/ResourcesController.cs +++ b/Moonlight/App/Http/Controllers/Api/Moonlight/ResourcesController.cs @@ -1,5 +1,7 @@ using Logging.Net; using Microsoft.AspNetCore.Mvc; +using Moonlight.App.Models.Misc; +using Moonlight.App.Services.LogServices; namespace Moonlight.App.Http.Controllers.Api.Moonlight; @@ -7,12 +9,19 @@ namespace Moonlight.App.Http.Controllers.Api.Moonlight; [Route("api/moonlight/resources")] public class ResourcesController : Controller { + private readonly SecurityLogService SecurityLogService; + + public ResourcesController(SecurityLogService securityLogService) + { + SecurityLogService = securityLogService; + } + [HttpGet("images/{name}")] - public ActionResult GetImage([FromRoute] string name) + public async Task GetImage([FromRoute] string name) { if (name.Contains("..")) { - //TODO: Add security warn + await SecurityLogService.Log(SecurityLogType.PathTransversal, name); return NotFound(); } diff --git a/Moonlight/App/Models/Misc/AuditLogType.cs b/Moonlight/App/Models/Misc/AuditLogType.cs index 80ee10d..cb5012c 100644 --- a/Moonlight/App/Models/Misc/AuditLogType.cs +++ b/Moonlight/App/Models/Misc/AuditLogType.cs @@ -4,5 +4,19 @@ public enum AuditLogType { Login, Register, - LoginFail + ChangePassword, + ChangePowerState, + CreateBackup, + RestoreBackup, + DeleteBackup, + DownloadBackup, + CreateServer, + ReinstallServer, + CancelSubscription, + ApplySubscriptionCode, + EnableTotp, + DisableTotp, + AddDomainRecord, + UpdateDomainRecord, + DeleteDomainRecord } \ No newline at end of file diff --git a/Moonlight/App/Models/Misc/SecurityLogType.cs b/Moonlight/App/Models/Misc/SecurityLogType.cs index a321a5c..74ea78c 100644 --- a/Moonlight/App/Models/Misc/SecurityLogType.cs +++ b/Moonlight/App/Models/Misc/SecurityLogType.cs @@ -2,5 +2,8 @@ public enum SecurityLogType { - ManipulatedJwt + ManipulatedJwt, + PathTransversal, + SftpBruteForce, + LoginFail } \ No newline at end of file diff --git a/Moonlight/App/Services/DomainService.cs b/Moonlight/App/Services/DomainService.cs index 08ee466..b2b2b1f 100644 --- a/Moonlight/App/Services/DomainService.cs +++ b/Moonlight/App/Services/DomainService.cs @@ -9,7 +9,9 @@ using Logging.Net; using Microsoft.EntityFrameworkCore; using Moonlight.App.Database.Entities; using Moonlight.App.Exceptions; +using Moonlight.App.Models.Misc; using Moonlight.App.Repositories.Domains; +using Moonlight.App.Services.LogServices; using DnsRecord = Moonlight.App.Models.Misc.DnsRecord; namespace Moonlight.App.Services; @@ -19,14 +21,18 @@ public class DomainService private readonly DomainRepository DomainRepository; private readonly SharedDomainRepository SharedDomainRepository; private readonly CloudFlareClient Client; + private readonly AuditLogService AuditLogService; private readonly string AccountId; - public DomainService(ConfigService configService, + public DomainService( + ConfigService configService, DomainRepository domainRepository, - SharedDomainRepository sharedDomainRepository) + SharedDomainRepository sharedDomainRepository, + AuditLogService auditLogService) { DomainRepository = domainRepository; SharedDomainRepository = sharedDomainRepository; + AuditLogService = auditLogService; var config = configService .GetSection("Moonlight") @@ -46,10 +52,10 @@ public class DomainService GetAvailableDomains() // This method returns all available domains which are not added as a shared domain { var domains = GetData( - await Client.Zones.GetAsync(new() - { - AccountId = AccountId - }) + await Client.Zones.GetAsync(new() + { + AccountId = AccountId + }) ); var sharedDomains = SharedDomainRepository.Get().ToArray(); @@ -82,7 +88,7 @@ public class DomainService { if (record.Name.EndsWith(dname)) { - result.Add(new () + result.Add(new() { Name = record.Name.Replace(dname, ""), Content = record.Content, @@ -95,7 +101,7 @@ public class DomainService } else if (record.Name.EndsWith(rname)) { - result.Add(new () + result.Add(new() { Name = record.Name.Replace(rname, ""), Content = record.Content, @@ -107,14 +113,14 @@ public class DomainService }); } } - + return result.ToArray(); } public async Task AddDnsRecord(Domain d, DnsRecord dnsRecord) { var domain = EnsureData(d); - + var rname = $"{domain.Name}.{domain.SharedDomain.Name}"; var dname = $".{rname}"; @@ -134,7 +140,6 @@ public class DomainService Type = dnsRecord.Type, Data = new() { - Service = parts[0], Protocol = protocol, Name = name, @@ -146,7 +151,7 @@ public class DomainService Proxied = dnsRecord.Proxied, Ttl = dnsRecord.Ttl, }; - + GetData(await Client.Zones.DnsRecords.AddAsync(d.SharedDomain.CloudflareId, srv)); } else @@ -163,32 +168,38 @@ public class DomainService Name = name })); } + + await AuditLogService.Log(AuditLogType.AddDomainRecord, new[] { d.Id.ToString(), dnsRecord.Name }); } - + public async Task UpdateDnsRecord(Domain d, DnsRecord dnsRecord) { var domain = EnsureData(d); - + var rname = $"{domain.Name}.{domain.SharedDomain.Name}"; var dname = $".{rname}"; if (dnsRecord.Type == DnsRecordType.Srv) { - throw new DisplayException("SRV records cannot be updated thanks to the cloudflare api client. Please delete the record and create a new one"); + throw new DisplayException( + "SRV records cannot be updated thanks to the cloudflare api client. Please delete the record and create a new one"); } else { var name = dnsRecord.Name == "" ? rname : dnsRecord.Name + dname; - - GetData(await Client.Zones.DnsRecords.UpdateAsync(d.SharedDomain.CloudflareId, dnsRecord.Id, new ModifiedDnsRecord() - { - Content = dnsRecord.Content, - Proxied = dnsRecord.Proxied, - Ttl = dnsRecord.Ttl, - Name = name, - Type = dnsRecord.Type - })); + + GetData(await Client.Zones.DnsRecords.UpdateAsync(d.SharedDomain.CloudflareId, dnsRecord.Id, + new ModifiedDnsRecord() + { + Content = dnsRecord.Content, + Proxied = dnsRecord.Proxied, + Ttl = dnsRecord.Ttl, + Name = name, + Type = dnsRecord.Type + })); } + + await AuditLogService.Log(AuditLogType.UpdateDomainRecord, new[] { d.Id.ToString(), dnsRecord.Name }); } public async Task DeleteDnsRecord(Domain d, DnsRecord dnsRecord) @@ -198,6 +209,8 @@ public class DomainService GetData( await Client.Zones.DnsRecords.DeleteAsync(domain.SharedDomain.CloudflareId, dnsRecord.Id) ); + + await AuditLogService.Log(AuditLogType.DeleteDomainRecord, new[] { d.Id.ToString(), dnsRecord.Name }); } private Domain EnsureData(Domain domain) @@ -210,12 +223,13 @@ public class DomainService .Include(x => x.SharedDomain) .First(x => x.Id == domain.Id); } + private T GetData(CloudFlareResult result) { if (!result.Success) { string message; - + try { message = result.Errors.First().ErrorChain.First().Message; diff --git a/Moonlight/App/Services/LogServices/AuditLogService.cs b/Moonlight/App/Services/LogServices/AuditLogService.cs index e1590e1..7e32f58 100644 --- a/Moonlight/App/Services/LogServices/AuditLogService.cs +++ b/Moonlight/App/Services/LogServices/AuditLogService.cs @@ -9,24 +9,26 @@ namespace Moonlight.App.Services.LogServices; public class AuditLogService { private readonly AuditLogEntryRepository Repository; - private readonly IdentityService IdentityService; + private readonly IHttpContextAccessor HttpContextAccessor; - public AuditLogService(AuditLogEntryRepository repository, IdentityService identityService) + public AuditLogService( + AuditLogEntryRepository repository, + IHttpContextAccessor httpContextAccessor) { Repository = repository; - IdentityService = identityService; + HttpContextAccessor = httpContextAccessor; } - public Task Log(AuditLogType type, object? data = null) + public Task Log(AuditLogType type, params object[] data) { - var ip = IdentityService.GetIp(); + var ip = GetIp(); var entry = new AuditLogEntry() { Ip = ip, Type = type, System = false, - JsonData = data == null ? "" : JsonConvert.SerializeObject(data) + JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data) }; Repository.Add(entry); @@ -34,17 +36,30 @@ public class AuditLogService return Task.CompletedTask; } - public Task LogSystem(AuditLogType type, object? data = null) + public Task LogSystem(AuditLogType type, params object[] data) { var entry = new AuditLogEntry() { Type = type, System = true, - JsonData = data == null ? "" : JsonConvert.SerializeObject(data) + JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data) }; Repository.Add(entry); return Task.CompletedTask; } + + private string GetIp() + { + if (HttpContextAccessor.HttpContext == null) + return "N/A"; + + if(HttpContextAccessor.HttpContext.Request.Headers.ContainsKey("X-Real-IP")) + { + return HttpContextAccessor.HttpContext.Request.Headers["X-Real-IP"]!; + } + + return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress!.ToString(); + } } \ No newline at end of file diff --git a/Moonlight/App/Services/LogServices/ErrorLogService.cs b/Moonlight/App/Services/LogServices/ErrorLogService.cs index 4530400..6c41945 100644 --- a/Moonlight/App/Services/LogServices/ErrorLogService.cs +++ b/Moonlight/App/Services/LogServices/ErrorLogService.cs @@ -10,17 +10,17 @@ namespace Moonlight.App.Services.LogServices; public class ErrorLogService { private readonly ErrorLogEntryRepository Repository; - private readonly IdentityService IdentityService; + private readonly IHttpContextAccessor HttpContextAccessor; - public ErrorLogService(ErrorLogEntryRepository repository, IdentityService identityService) + public ErrorLogService(ErrorLogEntryRepository repository, IHttpContextAccessor httpContextAccessor) { Repository = repository; - IdentityService = identityService; + HttpContextAccessor = httpContextAccessor; } public Task Log(Exception exception, params object[] objects) { - var ip = IdentityService.GetIp(); + var ip = GetIp(); var entry = new ErrorLogEntry() { @@ -74,4 +74,17 @@ public class ErrorLogService return fullName; } + + private string GetIp() + { + if (HttpContextAccessor.HttpContext == null) + return "N/A"; + + if(HttpContextAccessor.HttpContext.Request.Headers.ContainsKey("X-Real-IP")) + { + return HttpContextAccessor.HttpContext.Request.Headers["X-Real-IP"]!; + } + + return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress!.ToString(); + } } \ No newline at end of file diff --git a/Moonlight/App/Services/LogServices/SecurityLogService.cs b/Moonlight/App/Services/LogServices/SecurityLogService.cs index d085113..d276a2b 100644 --- a/Moonlight/App/Services/LogServices/SecurityLogService.cs +++ b/Moonlight/App/Services/LogServices/SecurityLogService.cs @@ -9,24 +9,24 @@ namespace Moonlight.App.Services.LogServices; public class SecurityLogService { private readonly SecurityLogEntryRepository Repository; - private readonly IdentityService IdentityService; + private readonly IHttpContextAccessor HttpContextAccessor; - public SecurityLogService(SecurityLogEntryRepository repository, IdentityService identityService) + public SecurityLogService(SecurityLogEntryRepository repository, IHttpContextAccessor httpContextAccessor) { Repository = repository; - IdentityService = identityService; + HttpContextAccessor = httpContextAccessor; } - public Task Log(SecurityLogType type, object? data = null) + public Task Log(SecurityLogType type, params object[] data) { - var ip = IdentityService.GetIp(); + var ip = GetIp(); var entry = new SecurityLogEntry() { Ip = ip, Type = type, System = false, - JsonData = data == null ? "" : JsonConvert.SerializeObject(data) + JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data) }; Repository.Add(entry); @@ -34,17 +34,30 @@ public class SecurityLogService return Task.CompletedTask; } - public Task LogSystem(SecurityLogType type, object? data = null) + public Task LogSystem(SecurityLogType type, params object[] data) { var entry = new SecurityLogEntry() { Type = type, System = true, - JsonData = data == null ? "" : JsonConvert.SerializeObject(data) + JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data) }; Repository.Add(entry); return Task.CompletedTask; } + + private string GetIp() + { + if (HttpContextAccessor.HttpContext == null) + return "N/A"; + + if(HttpContextAccessor.HttpContext.Request.Headers.ContainsKey("X-Real-IP")) + { + return HttpContextAccessor.HttpContext.Request.Headers["X-Real-IP"]!; + } + + return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress!.ToString(); + } } \ No newline at end of file diff --git a/Moonlight/App/Services/MessageService.cs b/Moonlight/App/Services/MessageService.cs index f063d93..1a4c853 100644 --- a/Moonlight/App/Services/MessageService.cs +++ b/Moonlight/App/Services/MessageService.cs @@ -6,6 +6,6 @@ public class MessageService : MessageSender { public MessageService() { - Debug = true; + Debug = false; } } \ No newline at end of file diff --git a/Moonlight/App/Services/OneTimeJwtService.cs b/Moonlight/App/Services/OneTimeJwtService.cs index 505596b..871a1b0 100644 --- a/Moonlight/App/Services/OneTimeJwtService.cs +++ b/Moonlight/App/Services/OneTimeJwtService.cs @@ -1,9 +1,12 @@ using System.Text; using JWT.Algorithms; using JWT.Builder; +using JWT.Exceptions; using Moonlight.App.Exceptions; using Moonlight.App.Helpers; +using Moonlight.App.Models.Misc; using Moonlight.App.Repositories; +using Moonlight.App.Services.LogServices; namespace Moonlight.App.Services; @@ -11,11 +14,15 @@ public class OneTimeJwtService { private readonly ConfigService ConfigService; private readonly RevokeRepository RevokeRepository; + private readonly SecurityLogService SecurityLogService; - public OneTimeJwtService(ConfigService configService, RevokeRepository revokeRepository) + public OneTimeJwtService(ConfigService configService, + RevokeRepository revokeRepository, + SecurityLogService securityLogService) { ConfigService = configService; RevokeRepository = revokeRepository; + SecurityLogService = securityLogService; } public string Generate(Action> options, TimeSpan? validTime = null) @@ -51,7 +58,7 @@ public class OneTimeJwtService return builder.Encode(); } - public Dictionary? Validate(string token) + public async Task?> Validate(string token) { string secret = ConfigService .GetSection("Moonlight") @@ -59,15 +66,18 @@ public class OneTimeJwtService .GetValue("Token"); string json; - + try { json = JwtBuilder.Create() .WithAlgorithm(new HMACSHA256Algorithm()) .WithSecret(secret) .Decode(token); - - //TODO: Error handling, report signature errors + } + catch (SignatureVerificationException) + { + await SecurityLogService.LogSystem(SecurityLogType.ManipulatedJwt, token); + return null; } catch (Exception e) { @@ -97,9 +107,9 @@ public class OneTimeJwtService return opt; } - public void Revoke(string token) + public async Task Revoke(string token) { - var values = Validate(token); + var values = await Validate(token); RevokeRepository.Add(new() { diff --git a/Moonlight/App/Services/ServerService.cs b/Moonlight/App/Services/ServerService.cs index aad5504..0542a09 100644 --- a/Moonlight/App/Services/ServerService.cs +++ b/Moonlight/App/Services/ServerService.cs @@ -6,11 +6,13 @@ using Moonlight.App.Exceptions; using Moonlight.App.Helpers; using Moonlight.App.Models.Files; using Moonlight.App.Models.Files.Accesses; +using Moonlight.App.Models.Misc; using Moonlight.App.Models.Wings; using Moonlight.App.Models.Wings.Requests; using Moonlight.App.Models.Wings.Resources; using Moonlight.App.Repositories; using Moonlight.App.Repositories.Servers; +using Moonlight.App.Services.LogServices; namespace Moonlight.App.Services; @@ -25,6 +27,9 @@ public class ServerService private readonly UserService UserService; private readonly ConfigService ConfigService; private readonly WingsJwtHelper WingsJwtHelper; + private readonly SecurityLogService SecurityLogService; + private readonly AuditLogService AuditLogService; + private readonly ErrorLogService ErrorLogService; private readonly string AppUrl; public ServerService( @@ -36,7 +41,10 @@ public class ServerService MessageService messageService, UserService userService, ConfigService configService, - WingsJwtHelper wingsJwtHelper) + WingsJwtHelper wingsJwtHelper, + SecurityLogService securityLogService, + AuditLogService auditLogService, + ErrorLogService errorLogService) { ServerRepository = serverRepository; WingsApiHelper = wingsApiHelper; @@ -47,6 +55,9 @@ public class ServerService UserService = userService; ConfigService = configService; WingsJwtHelper = wingsJwtHelper; + SecurityLogService = securityLogService; + AuditLogService = auditLogService; + ErrorLogService = errorLogService; AppUrl = ConfigService.GetSection("Moonlight").GetValue("AppUrl"); } @@ -84,6 +95,8 @@ public class ServerService { Action = rawSignal }); + + await AuditLogService.Log(AuditLogType.ChangePowerState, new[] { server.Uuid.ToString(), rawSignal }); } public async Task CreateBackup(Server server) @@ -112,6 +125,9 @@ public class ServerService Ignore = "" }); + await AuditLogService.Log(AuditLogType.CreateBackup, + new[] { serverData.Uuid.ToString(), backup.Uuid.ToString() }); + return backup; } @@ -146,6 +162,9 @@ public class ServerService { Adapter = "wings" }); + + await AuditLogService.Log(AuditLogType.RestoreBackup, + new[] { s.Uuid.ToString(), serverBackup.Uuid.ToString() }); } public async Task DeleteBackup(Server server, ServerBackup serverBackup) @@ -165,9 +184,12 @@ public class ServerService ServerRepository.Update(serverData); await MessageService.Emit("wings.backups.delete", backup); + + await AuditLogService.Log(AuditLogType.DeleteBackup, + new[] { serverBackup.Uuid.ToString(), serverBackup.Uuid.ToString() }); } - public Task DownloadBackup(Server s, ServerBackup serverBackup) + public async Task DownloadBackup(Server s, ServerBackup serverBackup) { Server server = EnsureNodeData(s); @@ -176,10 +198,11 @@ public class ServerService claims.Add("server_uuid", server.Uuid.ToString()); claims.Add("backup_uuid", serverBackup.Uuid.ToString()); }); + + await AuditLogService.Log(AuditLogType.DownloadBackup, + new[] { serverBackup.Uuid.ToString(), serverBackup.Uuid.ToString() }); - return Task.FromResult( - $"https://{server.Node.Fqdn}:{server.Node.HttpPort}/download/backup?token={token}" - ); + return $"https://{server.Node.Fqdn}:{server.Node.HttpPort}/download/backup?token={token}"; } public Task CreateFileAccess(Server s, User user) // We need the user to create the launch url @@ -197,7 +220,8 @@ public class ServerService ); } - public async Task Create(string name, int cpu, long memory, long disk, User u, Image i, Node? n = null, Action? modifyDetails = null) + public async Task Create(string name, int cpu, long memory, long disk, User u, Image i, Node? n = null, + Action? modifyDetails = null) { var user = UserRepository .Get() @@ -267,8 +291,8 @@ public class ServerService Value = imageVariable.DefaultValue }); } - - if(modifyDetails != null) + + if (modifyDetails != null) modifyDetails.Invoke(server); var newServerData = ServerRepository.Add(server); @@ -281,16 +305,17 @@ public class ServerService StartOnCompletion = false }); + await AuditLogService.Log(AuditLogType.CreateServer, newServerData.Uuid.ToString()); + return newServerData; } catch (Exception e) { - Logger.Error("Error creating server on wings. Deleting db model"); - Logger.Error(e); + await ErrorLogService.Log(e, new[] { newServerData.Uuid.ToString(), node.Id.ToString() }); ServerRepository.Delete(newServerData); - throw new Exception("Error creating server on wings"); + throw new DisplayException("Error creating server on wings"); } } @@ -299,14 +324,19 @@ public class ServerService Server server = EnsureNodeData(s); await WingsApiHelper.Post(server.Node, $"api/servers/{server.Uuid}/reinstall", null); + + await AuditLogService.Log(AuditLogType.ReinstallServer, server.Uuid.ToString()); } public async Task SftpServerLogin(int serverId, int id, string password) { var server = ServerRepository.Get().FirstOrDefault(x => x.Id == serverId); - if (server == null) //TODO: Logging + if (server == null) + { + await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, serverId); throw new Exception("Server not found"); + } var user = await UserService.SftpLogin(id, password); @@ -316,6 +346,7 @@ public class ServerService } else { + //TODO: Decide if logging throw new Exception("User and owner id do not match"); } } diff --git a/Moonlight/App/Services/Sessions/IdentityService.cs b/Moonlight/App/Services/Sessions/IdentityService.cs index 3b79a02..bce9382 100644 --- a/Moonlight/App/Services/Sessions/IdentityService.cs +++ b/Moonlight/App/Services/Sessions/IdentityService.cs @@ -4,7 +4,9 @@ using JWT.Builder; using JWT.Exceptions; using Logging.Net; using Moonlight.App.Database.Entities; +using Moonlight.App.Models.Misc; using Moonlight.App.Repositories; +using Moonlight.App.Services.LogServices; using UAParser; namespace Moonlight.App.Services.Sessions; @@ -13,6 +15,8 @@ public class IdentityService { private readonly UserRepository UserRepository; private readonly CookieService CookieService; + private readonly SecurityLogService SecurityLogService; + private readonly ErrorLogService ErrorLogService; private readonly IHttpContextAccessor HttpContextAccessor; private readonly string Secret; @@ -22,11 +26,15 @@ public class IdentityService CookieService cookieService, UserRepository userRepository, IHttpContextAccessor httpContextAccessor, - ConfigService configService) + ConfigService configService, + SecurityLogService securityLogService, + ErrorLogService errorLogService) { CookieService = cookieService; UserRepository = userRepository; HttpContextAccessor = httpContextAccessor; + SecurityLogService = securityLogService; + ErrorLogService = errorLogService; Secret = configService .GetSection("Moonlight") @@ -81,14 +89,12 @@ public class IdentityService } catch (SignatureVerificationException) { - //TODO: Heavy warn and write it to the logs - Logger.Warn("Someone tried to modify his data: " + token); + await SecurityLogService.Log(SecurityLogType.ManipulatedJwt, token); return null; } catch (Exception e) { - Logger.Warn("Error parsing and validating token"); - Logger.Warn(e); + await ErrorLogService.Log(e); return null; } @@ -117,19 +123,14 @@ public class IdentityService var issuedAt = DateTimeOffset.FromUnixTimeSeconds(iat).DateTime; if (issuedAt < user.TokenValidTime.ToUniversalTime()) - { - //TODO: Remove at publish - //Logger.Debug($"Old token found: {issuedAt.ToShortDateString()} {issuedAt.ToShortTimeString()} Current valid token time {userData.TokenValidTime.ToUniversalTime().ToShortDateString()} {userData.TokenValidTime.ToUniversalTime().ToShortTimeString()}"); return null; - } UserCache = user; return UserCache; } catch (Exception e) { - Logger.Warn("Error loading user"); - Logger.Warn(e); + await ErrorLogService.Log(e); return null; } } diff --git a/Moonlight/App/Services/SubscriptionService.cs b/Moonlight/App/Services/SubscriptionService.cs index 8555fdf..1627eca 100644 --- a/Moonlight/App/Services/SubscriptionService.cs +++ b/Moonlight/App/Services/SubscriptionService.cs @@ -1,8 +1,10 @@ using Microsoft.EntityFrameworkCore; using Moonlight.App.Database.Entities; using Moonlight.App.Exceptions; +using Moonlight.App.Models.Misc; using Moonlight.App.Repositories; using Moonlight.App.Repositories.Subscriptions; +using Moonlight.App.Services.LogServices; using Moonlight.App.Services.Sessions; namespace Moonlight.App.Services; @@ -14,18 +16,21 @@ public class SubscriptionService private readonly IdentityService IdentityService; private readonly ConfigService ConfigService; private readonly OneTimeJwtService OneTimeJwtService; + private readonly AuditLogService AuditLogService; public SubscriptionService(SubscriptionRepository subscriptionRepository, UserRepository userRepository, IdentityService identityService, ConfigService configService, - OneTimeJwtService oneTimeJwtService) + OneTimeJwtService oneTimeJwtService, + AuditLogService auditLogService) { SubscriptionRepository = subscriptionRepository; UserRepository = userRepository; IdentityService = identityService; ConfigService = configService; OneTimeJwtService = oneTimeJwtService; + AuditLogService = auditLogService; } public async Task Get() @@ -50,6 +55,8 @@ public class SubscriptionService var user = await IdentityService.Get(); user!.Subscription = null; UserRepository.Update(user!); + + await AuditLogService.Log(AuditLogType.CancelSubscription, new[] { user.Email }); } public Task GetAvailable() { @@ -91,7 +98,7 @@ public class SubscriptionService public async Task ApplyCode(string code) { var user = (await IdentityService.Get())!; - var values = OneTimeJwtService.Validate(code); + var values = await OneTimeJwtService.Validate(code); if (values == null) throw new DisplayException("Invalid subscription code"); @@ -114,6 +121,8 @@ public class SubscriptionService UserRepository.Update(user); - OneTimeJwtService.Revoke(code); + await OneTimeJwtService.Revoke(code); + + await AuditLogService.Log(AuditLogType.ApplySubscriptionCode, new[] { user.Email, subscription.Id.ToString() }); } } \ No newline at end of file diff --git a/Moonlight/App/Services/TotpService.cs b/Moonlight/App/Services/TotpService.cs index 4ca5c34..be76546 100644 --- a/Moonlight/App/Services/TotpService.cs +++ b/Moonlight/App/Services/TotpService.cs @@ -1,4 +1,6 @@ -using Moonlight.App.Repositories; +using Moonlight.App.Models.Misc; +using Moonlight.App.Repositories; +using Moonlight.App.Services.LogServices; using Moonlight.App.Services.Sessions; using OtpNet; @@ -8,11 +10,16 @@ public class TotpService { private readonly IdentityService IdentityService; private readonly UserRepository UserRepository; + private readonly AuditLogService AuditLogService; - public TotpService(IdentityService identityService, UserRepository userRepository) + public TotpService( + IdentityService identityService, + UserRepository userRepository, + AuditLogService auditLogService) { IdentityService = identityService; UserRepository = userRepository; + AuditLogService = auditLogService; } public Task Verify(string secret, string code) @@ -38,21 +45,25 @@ public class TotpService public async Task Enable() { - var user = await IdentityService.Get(); + var user = (await IdentityService.Get())!; user.TotpEnabled = true; user.TotpSecret = GenerateSecret(); UserRepository.Update(user); + + await AuditLogService.Log(AuditLogType.EnableTotp, user.Email); } public async Task Disable() { - var user = await IdentityService.Get(); + var user = (await IdentityService.Get())!; user.TotpEnabled = false; UserRepository.Update(user); + + await AuditLogService.Log(AuditLogType.DisableTotp, user.Email); } private string GenerateSecret() diff --git a/Moonlight/App/Services/UserService.cs b/Moonlight/App/Services/UserService.cs index 73fd7f9..0de40d8 100644 --- a/Moonlight/App/Services/UserService.cs +++ b/Moonlight/App/Services/UserService.cs @@ -1,10 +1,10 @@ using JWT.Algorithms; using JWT.Builder; -using Logging.Net; using Moonlight.App.Database.Entities; using Moonlight.App.Exceptions; using Moonlight.App.Models.Misc; using Moonlight.App.Repositories; +using Moonlight.App.Services.LogServices; namespace Moonlight.App.Services; @@ -12,20 +12,24 @@ public class UserService { private readonly UserRepository UserRepository; private readonly TotpService TotpService; - private readonly ConfigService ConfigService; + private readonly SecurityLogService SecurityLogService; + private readonly AuditLogService AuditLogService; private readonly string JwtSecret; public UserService( UserRepository userRepository, TotpService totpService, - ConfigService configService) + ConfigService configService, + SecurityLogService securityLogService, + AuditLogService auditLogService) { UserRepository = userRepository; TotpService = totpService; - ConfigService = configService; + SecurityLogService = securityLogService; + AuditLogService = auditLogService; - JwtSecret = ConfigService + JwtSecret = configService .GetSection("Moonlight") .GetSection("Security") .GetValue("Token"); @@ -67,11 +71,13 @@ public class UserService //var mail = new WelcomeMail(user); //await MailService.Send(mail, user); + + await AuditLogService.Log(AuditLogType.Register, user.Email); return await GenerateToken(user); } - public Task CheckTotp(string email, string password) + public async Task CheckTotp(string email, string password) { var user = UserRepository.Get() .FirstOrDefault( @@ -80,18 +86,16 @@ public class UserService if (user == null) { - Logger.Debug("User not found"); - - //AuditLogService.Log("login:fail", $"Invalid email: {email}. Password: {password}"); + await SecurityLogService.Log(SecurityLogType.LoginFail, new[] { email, password }); throw new DisplayException("Email and password combination not found"); } if (BCrypt.Net.BCrypt.Verify(password, user.Password)) { - return Task.FromResult(user.TotpEnabled); + return user.TotpEnabled; } - //AuditLogService.Log("login:fail", $"Invalid email: {email}. Password: {password}"); + await SecurityLogService.Log(SecurityLogType.LoginFail, new[] { email, password }); throw new DisplayException("Email and password combination not found");; } @@ -111,29 +115,27 @@ public class UserService if (string.IsNullOrEmpty(totpCode)) throw new DisplayException("2FA code must be provided"); - var totpCodeValid = await TotpService.Verify(user.TotpSecret, totpCode); + var totpCodeValid = await TotpService.Verify(user!.TotpSecret, totpCode); if (totpCodeValid) { - //AuditLogService.Log("login:success", $"{user.Email} has successfully logged in"); - + await AuditLogService.Log(AuditLogType.Login, email); return await GenerateToken(user); } else { - //AuditLogService.Log("login:fail", $"Invalid totp code: {totpCode}"); + await SecurityLogService.Log(SecurityLogType.LoginFail, new[] { email, password }); throw new DisplayException("2FA code invalid"); } } else { - //AuditLogService.Log("login:success", $"{user.Email} has successfully logged in"); - + await AuditLogService.Log(AuditLogType.Login, email); return await GenerateToken(user!); } } - public Task ChangePassword(User user, string password) + public async Task ChangePassword(User user, string password) { user.Password = BCrypt.Net.BCrypt.HashPassword(password); user.TokenValidTime = DateTime.Now; @@ -141,26 +143,27 @@ public class UserService //var mail = new NewPasswordMail(user); //await MailService.Send(mail, user); - - //AuditLogService.Log("password:change", "The password has been set to a new one"); - - return Task.CompletedTask; + + await AuditLogService.Log(AuditLogType.ChangePassword, user.Email); } - public Task SftpLogin(int id, string password) + public async Task SftpLogin(int id, string password) { var user = UserRepository.Get().FirstOrDefault(x => x.Id == id); if (user == null) - throw new Exception("Unknown user"); + { + await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, id); + throw new Exception("Invalid username"); + } if (BCrypt.Net.BCrypt.Verify(password, user.Password)) { - //TODO: Maybe log - return Task.FromResult(user); + await AuditLogService.LogSystem(AuditLogType.Login, user.Email); + return user; } - //TODO: Log + await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, new[] { id.ToString(), password }); throw new Exception("Invalid userid or password"); } diff --git a/Moonlight/Program.cs b/Moonlight/Program.cs index b57cd95..6abba75 100644 --- a/Moonlight/Program.cs +++ b/Moonlight/Program.cs @@ -10,6 +10,7 @@ using Moonlight.App.Repositories.Servers; using Moonlight.App.Repositories.Subscriptions; using Moonlight.App.Services; using Moonlight.App.Services.Interop; +using Moonlight.App.Services.LogServices; using Moonlight.App.Services.Notifications; using Moonlight.App.Services.OAuth2; using Moonlight.App.Services.Sessions; @@ -80,7 +81,10 @@ namespace Moonlight builder.Services.AddScoped(); builder.Services.AddScoped(); - + // Loggers + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); // Support builder.Services.AddSingleton(); diff --git a/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryChangePassword.razor b/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryChangePassword.razor new file mode 100644 index 0000000..b3ffcd8 --- /dev/null +++ b/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryChangePassword.razor @@ -0,0 +1,57 @@ +@using Moonlight.App.Database.Entities.LogsEntries +@using Moonlight.App.Helpers +@using Moonlight.App.Repositories +@using Newtonsoft.Json +@using Moonlight.App.Database.Entities + +@inject UserRepository UserRepository + +
+
+
+
+ +
+
+
+
+
+ @if (User == null) + { + Password change for @(Data[0]) + } + else + { + Password change for @(User.Email) + } +
+
+
@(Formatter.FormatDate(Entry.CreatedAt)), @(Entry.System ? "System" : Entry.Ip)
+
+
+
+
+ +@code +{ + [Parameter] + public AuditLogEntry Entry { get; set; } + + private User? User; + private string[] Data; + + protected override void OnInitialized() + { + Data = JsonConvert.DeserializeObject(Entry.JsonData)!; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + User = UserRepository.Get().FirstOrDefault(x => x.Email == Data[0]); + + await InvokeAsync(StateHasChanged); + } + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryChangePowerState.razor b/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryChangePowerState.razor new file mode 100644 index 0000000..9540015 --- /dev/null +++ b/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryChangePowerState.razor @@ -0,0 +1,57 @@ +@using Moonlight.App.Database.Entities.LogsEntries +@using Moonlight.App.Helpers +@using Newtonsoft.Json +@using Moonlight.App.Database.Entities +@using Moonlight.App.Repositories.Servers + +@inject ServerRepository ServerRepository + +
+
+
+
+ +
+
+
+
+
+ @if (Server == null) + { + Change power state for @(Data[0]) to @(Data[1]) + } + else + { + Change power state for @(Server.Name) to @(Data[1]) + } +
+
+
@(Formatter.FormatDate(Entry.CreatedAt)), @(Entry.System ? "System" : Entry.Ip)
+
+
+
+
+ +@code +{ + [Parameter] + public AuditLogEntry Entry { get; set; } + + private Server? Server; + private string[] Data; + + protected override void OnInitialized() + { + Data = JsonConvert.DeserializeObject(Entry.JsonData)!; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + Server = ServerRepository.Get().FirstOrDefault(x => x.Uuid == Guid.Parse(Data[0])); + + await InvokeAsync(StateHasChanged); + } + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryLogin.razor b/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryLogin.razor new file mode 100644 index 0000000..c215f4d --- /dev/null +++ b/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryLogin.razor @@ -0,0 +1,57 @@ +@using Moonlight.App.Database.Entities.LogsEntries +@using Moonlight.App.Helpers +@using Moonlight.App.Repositories +@using Newtonsoft.Json +@using Moonlight.App.Database.Entities + +@inject UserRepository UserRepository + +
+
+
+
+ +
+
+
+
+
+ @if (User == null) + { + New login for @(Data[0]) + } + else + { + New login for @(User.Email) + } +
+
+
@(Formatter.FormatDate(Entry.CreatedAt)), @(Entry.System ? "System" : Entry.Ip)
+
+
+
+
+ +@code +{ + [Parameter] + public AuditLogEntry Entry { get; set; } + + private User? User; + private string[] Data; + + protected override void OnInitialized() + { + Data = JsonConvert.DeserializeObject(Entry.JsonData)!; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + User = UserRepository.Get().FirstOrDefault(x => x.Email == Data[0]); + + await InvokeAsync(StateHasChanged); + } + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryRegister.razor b/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryRegister.razor new file mode 100644 index 0000000..43cc89a --- /dev/null +++ b/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryRegister.razor @@ -0,0 +1,57 @@ +@using Moonlight.App.Database.Entities.LogsEntries +@using Moonlight.App.Helpers +@using Moonlight.App.Repositories +@using Newtonsoft.Json +@using Moonlight.App.Database.Entities + +@inject UserRepository UserRepository + +
+
+
+
+ +
+
+
+
+
+ @if (User == null) + { + Register for @(Data[0]) + } + else + { + Register for @(User.Email) + } +
+
+
@(Formatter.FormatDate(Entry.CreatedAt)), @(Entry.System ? "System" : Entry.Ip)
+
+
+
+
+ +@code +{ + [Parameter] + public AuditLogEntry Entry { get; set; } + + private User? User; + private string[] Data; + + protected override void OnInitialized() + { + Data = JsonConvert.DeserializeObject(Entry.JsonData)!; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + User = UserRepository.Get().FirstOrDefault(x => x.Email == Data[0]); + + await InvokeAsync(StateHasChanged); + } + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Components/ErrorBoundaries/ComponentErrorBoundary.razor b/Moonlight/Shared/Components/ErrorBoundaries/ComponentErrorBoundary.razor index ae4bb92..d8f29c9 100644 --- a/Moonlight/Shared/Components/ErrorBoundaries/ComponentErrorBoundary.razor +++ b/Moonlight/Shared/Components/ErrorBoundaries/ComponentErrorBoundary.razor @@ -1,9 +1,10 @@ @using Logging.Net +@using Moonlight.App.Services.LogServices @using Moonlight.App.Services.Sessions @inherits ErrorBoundary -@inject IdentityService IdentityService +@inject ErrorLogService ErrorLogService @if (CurrentException is null) { @@ -52,13 +53,7 @@ else { receivedExceptions.Add(exception); - var user = await IdentityService.Get(); - var id = user == null ? -1 : user.Id; - - Logger.Error($"[{id}] An unhanded exception occured:"); - Logger.Error(exception); - - //TODO: Create error report + await ErrorLogService.Log(exception); await base.OnErrorAsync(exception); } diff --git a/Moonlight/Shared/Components/ErrorBoundaries/SoftErrorBoundary.razor b/Moonlight/Shared/Components/ErrorBoundaries/SoftErrorBoundary.razor index d89d369..ca47b59 100644 --- a/Moonlight/Shared/Components/ErrorBoundaries/SoftErrorBoundary.razor +++ b/Moonlight/Shared/Components/ErrorBoundaries/SoftErrorBoundary.razor @@ -13,6 +13,8 @@ { protected override async Task OnErrorAsync(Exception exception) { + Logger.Debug(exception); + if (exception is DisplayException displayException) { await AlertService.Error( diff --git a/Moonlight/Shared/Components/Navigations/AdminSystemNavigation.razor b/Moonlight/Shared/Components/Navigations/AdminSystemNavigation.razor new file mode 100644 index 0000000..3719a5e --- /dev/null +++ b/Moonlight/Shared/Components/Navigations/AdminSystemNavigation.razor @@ -0,0 +1,25 @@ +@using Moonlight.App.Database.Entities +@using Moonlight.App.Models.Misc + +
+ +
+ +@code +{ + [Parameter] + public int Index { get; set; } = 0; +} \ No newline at end of file diff --git a/Moonlight/Shared/Components/Partials/SidebarMenu.razor b/Moonlight/Shared/Components/Partials/SidebarMenu.razor index b75a29d..37cd207 100644 --- a/Moonlight/Shared/Components/Partials/SidebarMenu.razor +++ b/Moonlight/Shared/Components/Partials/SidebarMenu.razor @@ -93,7 +93,7 @@ else diff --git a/Moonlight/Shared/Views/Admin/Sys/AuditLog.razor b/Moonlight/Shared/Views/Admin/Sys/AuditLog.razor new file mode 100644 index 0000000..48a60ce --- /dev/null +++ b/Moonlight/Shared/Views/Admin/Sys/AuditLog.razor @@ -0,0 +1,106 @@ +@page "/admin/system/auditlog" + +@using Moonlight.Shared.Components.Navigations +@using Moonlight.App.Repositories.LogEntries +@using Moonlight.App.Services +@using Moonlight.App.Database.Entities.LogsEntries +@using BlazorTable +@using Moonlight.App.Helpers +@using Moonlight.App.Models.Misc +@using Moonlight.Shared.Components.AuditLogEntrys + +@inject AuditLogEntryRepository AuditLogEntryRepository + + + + +
+
+
+ + + +

@(Formatter.FormatDateOnly(DateTime))

+
+
+ +
+
+
+ + @if (AuditLogEntries.Any()) + { +
+ @foreach (var entry in AuditLogEntries) + { + switch (entry.Type) + { + case AuditLogType.Login: + + break; + case AuditLogType.Register: + + break; + case AuditLogType.ChangePassword: + + break; + case AuditLogType.ChangePowerState: + + break; + } + } +
+ } + else + { +
+ No records found for this day +
+ } +
+
+
+
+ +@code +{ + private AuditLogEntry[] AuditLogEntries; + private LazyLoader LazyLoader; + private DateTime DateTime = DateTime.Today; + + private Task Load(LazyLoader arg) + { + AuditLogEntries = AuditLogEntryRepository + .Get() + .Where(x => x.CreatedAt.Date == DateTime.Date) + .OrderByDescending(x => x.Id) + .ToArray(); + + return Task.CompletedTask; + } + + private async Task Left() + { + DateTime = DateTime.AddDays(1); + + await LazyLoader.Reload(); + } + + private async Task Right() + { + DateTime = DateTime.AddDays(-1); + + await LazyLoader.Reload(); + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Views/Admin/Sys/Index.razor b/Moonlight/Shared/Views/Admin/Sys/Index.razor new file mode 100644 index 0000000..8fbe9c9 --- /dev/null +++ b/Moonlight/Shared/Views/Admin/Sys/Index.razor @@ -0,0 +1,9 @@ +@page "/admin/system" + +@using Moonlight.Shared.Components.Navigations + + + + + + \ No newline at end of file diff --git a/Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig b/Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig index fa454eb..136c3a0 100644 --- a/Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig +++ b/Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig @@ -31,6 +31,10 @@ build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQWxlcnRzXFNldHVwQ29tcGxldGVkQWxlcnQucmF6b3I= build_metadata.AdditionalFiles.CssScope = +[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryLogin.razor] +build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXVkaXRMb2dFbnRyeXNcQXVkaXRMb2dFbnRyeUxvZ2luLnJhem9y +build_metadata.AdditionalFiles.CssScope = + [C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/Auth/Login.razor] build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXV0aFxMb2dpbi5yYXpvcg== build_metadata.AdditionalFiles.CssScope = @@ -67,6 +71,10 @@ build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcRm9ybXNcV0J1dHRvbi5yYXpvcg== build_metadata.AdditionalFiles.CssScope = +[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/Navigations/AdminSystemNavigation.razor] +build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcTmF2aWdhdGlvbnNcQWRtaW5TeXN0ZW1OYXZpZ2F0aW9uLnJhem9y +build_metadata.AdditionalFiles.CssScope = + [C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/Navigations/ProfileNavigation.razor] build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcTmF2aWdhdGlvbnNcUHJvZmlsZU5hdmlnYXRpb24ucmF6b3I= build_metadata.AdditionalFiles.CssScope = @@ -227,6 +235,18 @@ build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN1cHBvcnRcVmlldy5yYXpvcg== build_metadata.AdditionalFiles.CssScope = +[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Admin/Sys/AuditLog.razor] +build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xBdWRpdExvZy5yYXpvcg== +build_metadata.AdditionalFiles.CssScope = + +[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Admin/Sys/Index.razor] +build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xJbmRleC5yYXpvcg== +build_metadata.AdditionalFiles.CssScope = + +[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Admin/Sys/Logging.razor] +build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xMb2dnaW5nLnJhem9y +build_metadata.AdditionalFiles.CssScope = + [C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Domains.razor] build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXERvbWFpbnMucmF6b3I= build_metadata.AdditionalFiles.CssScope = diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index 70671f5..7bcedc6 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -257,3 +257,13 @@ Cancel Subscription;Cancel Subscription Active until;Active until We will send you a notification upon subscription expiration;We will send you a notification upon subscription expiration This token has been already used;This token has been already used +New login for;New login for +No records found for this day;No records found for this day +Change;Change +Changing;Changing +Minecraft version;Minecraft version +Build version;Build version +Server installation is currently running;Server installation is currently running +Selected;Selected +Move deleted;Move deleted +Delete selected;Delete selected