Compare commits
254 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f48ec2245c | ||
|
|
37a3a35120 | ||
|
|
c549d45d54 | ||
|
|
42a011541c | ||
|
|
71a8839f5f | ||
|
|
b99e8b5476 | ||
|
|
5793bd9747 | ||
|
|
24ce51a62e | ||
|
|
762d3cc1a1 | ||
|
|
ea19105006 | ||
|
|
a372c756e4 | ||
|
|
18b7c82613 | ||
|
|
5d91077d42 | ||
|
|
c0872d0d02 | ||
|
|
00722c4046 | ||
|
|
f16a29dafb | ||
|
|
6da8393612 | ||
|
|
2ef00b81b8 | ||
|
|
0be4ebc7ff | ||
|
|
e0d5e754b7 | ||
|
|
6972c2bb32 | ||
|
|
95ba81eab4 | ||
|
|
b9c094cafa | ||
|
|
bada1e829b | ||
|
|
1d33cf3110 | ||
|
|
abfcefba60 | ||
|
|
6efb443481 | ||
|
|
10c017932a | ||
|
|
a4be4bdc52 | ||
|
|
88d5a1de86 | ||
|
|
1b88827d16 | ||
|
|
12e25dc4bc | ||
|
|
37c3fc7a53 | ||
|
|
0c6cbe0ba7 | ||
|
|
5cf63240a3 | ||
|
|
4d04d12a39 | ||
|
|
b846b28802 | ||
|
|
b94217abc0 | ||
|
|
de0d6a3808 | ||
|
|
eca9b6ec52 | ||
|
|
b6e048e982 | ||
|
|
b8b2ae7865 | ||
|
|
0611988019 | ||
|
|
f9fd7199b6 | ||
|
|
6ff4861fc6 | ||
|
|
2db7748703 | ||
|
|
87744e4846 | ||
|
|
ce7125b50b | ||
|
|
31d8c3f469 | ||
|
|
c80622c2fd | ||
|
|
95e659e5f7 | ||
|
|
c155909e82 | ||
|
|
0011ed29b7 | ||
|
|
52c4ca0c0a | ||
|
|
c197d0ca96 | ||
|
|
25902034e9 | ||
|
|
b10db643fe | ||
|
|
4c7ffe6714 | ||
|
|
a0c2b45a61 | ||
|
|
e49a9d3505 | ||
|
|
7ddae9c3e1 | ||
|
|
290e865ae0 | ||
|
|
00ee625e2e | ||
|
|
274e2d93f2 | ||
|
|
781171f7c5 | ||
|
|
4a8618da79 | ||
|
|
296cf0db6f | ||
|
|
48cdba5155 | ||
|
|
35c1b255b5 | ||
|
|
244b920305 | ||
|
|
3d4a2128e2 | ||
|
|
1cf8430ad8 | ||
|
|
a9b7d10fb0 | ||
|
|
47e333630e | ||
|
|
8b41a9fc13 | ||
|
|
d09957fdac | ||
|
|
f9ecb61d71 | ||
|
|
ef92dd47ad | ||
|
|
c2c533675b | ||
|
|
569dd69bdd | ||
|
|
242870b3e1 | ||
|
|
30b6e45235 | ||
|
|
cd62fdc5f6 | ||
|
|
2c54b91e6c | ||
|
|
388deacf60 | ||
|
|
aa547038de | ||
|
|
78bfd68d63 | ||
|
|
17e3345b8a | ||
|
|
f95312c1e3 | ||
|
|
2144ca3823 | ||
|
|
de45ff40d8 | ||
|
|
606085c012 | ||
|
|
00525d8099 | ||
|
|
26617d67f5 | ||
|
|
600bec3417 | ||
|
|
4e85d1755a | ||
|
|
0832936933 | ||
|
|
ecda2ec6d1 | ||
|
|
6f3765a3bf | ||
|
|
29002d3445 | ||
|
|
6d0456a008 | ||
|
|
3e698123bb | ||
|
|
f3fb86819a | ||
|
|
e2248a8444 | ||
|
|
2cf2b77090 | ||
|
|
fedc9278d4 | ||
|
|
f29206a69b | ||
|
|
0658e55a78 | ||
|
|
21bea974a9 | ||
|
|
33ef09433e | ||
|
|
173bff67df | ||
|
|
512a989609 | ||
|
|
2d7dac5089 | ||
|
|
11708fbc3b | ||
|
|
daeb4dd5b9 | ||
|
|
daba4cba04 | ||
|
|
1cd0f0f96f | ||
|
|
6a30db07a7 | ||
|
|
6c8754d008 | ||
|
|
356ba94592 | ||
|
|
d3b55d155b | ||
|
|
0015001d7c | ||
|
|
0a86aa8aa4 | ||
|
|
74d4ee729d | ||
|
|
178ff36e86 | ||
|
|
f852df5807 | ||
|
|
90f4b04857 | ||
|
|
244e87ed18 | ||
|
|
80ea5a543f | ||
|
|
5baba05f5f | ||
|
|
591da6de5c | ||
|
|
c1ddff4ae3 | ||
|
|
67d78d7104 | ||
|
|
52f4b00f84 | ||
|
|
8f028e2ac6 | ||
|
|
5bd6f15203 | ||
|
|
4c39ad6170 | ||
|
|
12392d4f47 | ||
|
|
b75147e4c0 | ||
|
|
8f9508f30b | ||
|
|
428e2668d3 | ||
|
|
c1cfb35c86 | ||
|
|
d6777c463e | ||
|
|
f9126bffe0 | ||
|
|
0488e83a38 | ||
|
|
d87ddc90e3 | ||
|
|
151bc82998 | ||
|
|
e4c21c74a5 | ||
|
|
13741a2be9 | ||
|
|
c866e89b72 | ||
|
|
8be93bc53c | ||
|
|
384b6a3e7d | ||
|
|
ba2de54c60 | ||
|
|
bd5567e24f | ||
|
|
b8e39824b5 | ||
|
|
d8c9bdbd8d | ||
|
|
80eb210af0 | ||
|
|
a295354549 | ||
|
|
749ea5dc8e | ||
|
|
f52b9e2951 | ||
|
|
d2dbb68967 | ||
|
|
d1c9009e9f | ||
|
|
d024a834f9 | ||
|
|
c0df8ac507 | ||
|
|
ab529991fd | ||
|
|
92705837ba | ||
|
|
609d5451f9 | ||
|
|
2bb2caeeed | ||
|
|
61db49bfb7 | ||
|
|
a75678d305 | ||
|
|
d418c91efa | ||
|
|
7f2da5a55d | ||
|
|
5e592ccdcb | ||
|
|
016f50fb1c | ||
|
|
fe21668a2b | ||
|
|
1aab86a317 | ||
|
|
243d23d4e2 | ||
|
|
2fe17473ae | ||
|
|
609cf8cfac | ||
|
|
678da30b09 | ||
|
|
d19412f4bb | ||
|
|
1665d6e537 | ||
|
|
fd210f2404 | ||
|
|
c33729fb44 | ||
|
|
7983bf3ee4 | ||
|
|
a09f60aea7 | ||
|
|
28b5893c21 | ||
|
|
25b47d8b6c | ||
|
|
85f5b8a7da | ||
|
|
ab9333f99a | ||
|
|
d60f8fc905 | ||
|
|
fe1f4412d8 | ||
|
|
f191533410 | ||
|
|
a894707536 | ||
|
|
d2ccc84286 | ||
|
|
f2ec43f2d2 | ||
|
|
7feccc8d9f | ||
|
|
a8bd1193ce | ||
|
|
366d1a9205 | ||
|
|
df9ed95c6b | ||
|
|
23a211362e | ||
|
|
cf91d44902 | ||
|
|
35633e21a9 | ||
|
|
ce8b8f6798 | ||
|
|
c28c80ba25 | ||
|
|
da17b1df93 | ||
|
|
f9f5865ef9 | ||
|
|
389ded9b77 | ||
|
|
faebaa59dd | ||
|
|
6b7dc2ad05 | ||
|
|
e356c9d0c8 | ||
|
|
efed2a6a5c | ||
|
|
6f138c2c51 | ||
|
|
6c43e6a533 | ||
|
|
0379afd831 | ||
|
|
b8bfdb7729 | ||
|
|
72f60ec97c | ||
|
|
1b40250750 | ||
|
|
cdf2988cb6 | ||
|
|
76415b4a0a | ||
|
|
52d00baf2b | ||
|
|
cd41db510e | ||
|
|
1afd4e8b92 | ||
|
|
ef37088c7a | ||
|
|
e71495533b | ||
|
|
e2a6d70f6a | ||
|
|
e95853b09c | ||
|
|
0537ca115e | ||
|
|
432e441972 | ||
|
|
1dae5150bd | ||
|
|
72c6f636ee | ||
|
|
e54d04277d | ||
|
|
f559f08e8d | ||
|
|
2674fb3fa7 | ||
|
|
d5d77ae7da | ||
|
|
3ae905038c | ||
|
|
6707d722e0 | ||
|
|
bc9fecf6d9 | ||
|
|
c2cb10f069 | ||
|
|
cc06d1eb0b | ||
|
|
916ff71022 | ||
|
|
9e80342e26 | ||
|
|
0fb97683bf | ||
|
|
32415bad54 | ||
|
|
d2b0bcc4a3 | ||
|
|
2f4f4193d3 | ||
|
|
7279f05a16 | ||
|
|
3962723acb | ||
|
|
125e72fa58 | ||
|
|
880cce060f | ||
|
|
0e04942111 | ||
|
|
46a88d4638 | ||
| 0fde9a5005 | |||
|
|
74541d7f87 |
8
.gitattributes
vendored
8
.gitattributes
vendored
@@ -1,2 +1,10 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
Moonlight/wwwroot/** linguist-vendored
|
||||
Moonlight/wwwroot/assets/js/scripts.bundle.js linguist-vendored
|
||||
Moonlight/wwwroot/assets/js/widgets.bundle.js linguist-vendored
|
||||
Moonlight/wwwroot/assets/js/theme.js linguist-vendored
|
||||
Moonlight/wwwroot/assets/css/boxicons.min.css linguist-vendored
|
||||
Moonlight/wwwroot/assets/css/style.bundle.css linguist-vendored
|
||||
Moonlight/wwwroot/assets/plugins/** linguist-vendored
|
||||
Moonlight/wwwroot/assets/fonts/** linguist-vendored
|
||||
|
||||
58
Moonlight/App/ApiClients/Modrinth/ModrinthApiHelper.cs
Normal file
58
Moonlight/App/ApiClients/Modrinth/ModrinthApiHelper.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using Newtonsoft.Json;
|
||||
using RestSharp;
|
||||
|
||||
namespace Moonlight.App.ApiClients.Modrinth;
|
||||
|
||||
public class ModrinthApiHelper
|
||||
{
|
||||
private readonly RestClient Client;
|
||||
|
||||
public ModrinthApiHelper()
|
||||
{
|
||||
Client = new();
|
||||
Client.AddDefaultParameter(
|
||||
new HeaderParameter("User-Agent", "Moonlight-Panel/Moonlight (admin@endelon-hosting.de)")
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<T> Get<T>(string resource)
|
||||
{
|
||||
var request = CreateRequest(resource);
|
||||
|
||||
request.Method = Method.Get;
|
||||
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
if (response.StatusCode != 0)
|
||||
{
|
||||
throw new ModrinthException(
|
||||
$"An error occured: ({response.StatusCode}) {response.Content}",
|
||||
(int)response.StatusCode
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"An internal error occured: {response.ErrorMessage}");
|
||||
}
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(response.Content!)!;
|
||||
}
|
||||
|
||||
private RestRequest CreateRequest(string resource)
|
||||
{
|
||||
var url = "https://api.modrinth.com/v2/" + resource;
|
||||
|
||||
var request = new RestRequest(url)
|
||||
{
|
||||
Timeout = 300000
|
||||
};
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
19
Moonlight/App/ApiClients/Modrinth/ModrinthException.cs
Normal file
19
Moonlight/App/ApiClients/Modrinth/ModrinthException.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Moonlight.App.ApiClients.Modrinth;
|
||||
|
||||
public class ModrinthException : Exception
|
||||
{
|
||||
public int StatusCode { get; set; }
|
||||
|
||||
public ModrinthException()
|
||||
{
|
||||
}
|
||||
|
||||
public ModrinthException(string message, int statusCode) : base(message)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
}
|
||||
|
||||
public ModrinthException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
}
|
||||
}
|
||||
14
Moonlight/App/ApiClients/Modrinth/Resources/Pagination.cs
Normal file
14
Moonlight/App/ApiClients/Modrinth/Resources/Pagination.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.ApiClients.Modrinth.Resources;
|
||||
|
||||
public class Pagination
|
||||
{
|
||||
[JsonProperty("hits")] public Project[] Hits { get; set; }
|
||||
|
||||
[JsonProperty("offset")] public long Offset { get; set; }
|
||||
|
||||
[JsonProperty("limit")] public long Limit { get; set; }
|
||||
|
||||
[JsonProperty("total_hits")] public long TotalHits { get; set; }
|
||||
}
|
||||
48
Moonlight/App/ApiClients/Modrinth/Resources/Project.cs
Normal file
48
Moonlight/App/ApiClients/Modrinth/Resources/Project.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.ApiClients.Modrinth.Resources;
|
||||
|
||||
public class Project
|
||||
{
|
||||
[JsonProperty("project_id")] public string ProjectId { get; set; }
|
||||
|
||||
[JsonProperty("project_type")] public string ProjectType { get; set; }
|
||||
|
||||
[JsonProperty("slug")] public string Slug { get; set; }
|
||||
|
||||
[JsonProperty("author")] public string Author { get; set; }
|
||||
|
||||
[JsonProperty("title")] public string Title { get; set; }
|
||||
|
||||
[JsonProperty("description")] public string Description { get; set; }
|
||||
|
||||
[JsonProperty("categories")] public string[] Categories { get; set; }
|
||||
|
||||
[JsonProperty("display_categories")] public string[] DisplayCategories { get; set; }
|
||||
|
||||
[JsonProperty("versions")] public string[] Versions { get; set; }
|
||||
|
||||
[JsonProperty("downloads")] public long Downloads { get; set; }
|
||||
|
||||
[JsonProperty("follows")] public long Follows { get; set; }
|
||||
|
||||
[JsonProperty("icon_url")] public string IconUrl { get; set; }
|
||||
|
||||
[JsonProperty("date_created")] public DateTimeOffset DateCreated { get; set; }
|
||||
|
||||
[JsonProperty("date_modified")] public DateTimeOffset DateModified { get; set; }
|
||||
|
||||
[JsonProperty("latest_version")] public string LatestVersion { get; set; }
|
||||
|
||||
[JsonProperty("license")] public string License { get; set; }
|
||||
|
||||
[JsonProperty("client_side")] public string ClientSide { get; set; }
|
||||
|
||||
[JsonProperty("server_side")] public string ServerSide { get; set; }
|
||||
|
||||
[JsonProperty("gallery")] public Uri[] Gallery { get; set; }
|
||||
|
||||
[JsonProperty("featured_gallery")] public Uri FeaturedGallery { get; set; }
|
||||
|
||||
[JsonProperty("color")] public long? Color { get; set; }
|
||||
}
|
||||
57
Moonlight/App/ApiClients/Modrinth/Resources/Version.cs
Normal file
57
Moonlight/App/ApiClients/Modrinth/Resources/Version.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.ApiClients.Modrinth.Resources;
|
||||
|
||||
public class Version
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("version_number")]
|
||||
public string VersionNumber { get; set; }
|
||||
|
||||
[JsonProperty("changelog")]
|
||||
public string Changelog { get; set; }
|
||||
|
||||
[JsonProperty("dependencies")]
|
||||
public object[] Dependencies { get; set; }
|
||||
|
||||
[JsonProperty("game_versions")]
|
||||
public object[] GameVersions { get; set; }
|
||||
|
||||
[JsonProperty("version_type")]
|
||||
public string VersionType { get; set; }
|
||||
|
||||
[JsonProperty("loaders")]
|
||||
public object[] Loaders { get; set; }
|
||||
|
||||
[JsonProperty("featured")]
|
||||
public bool Featured { get; set; }
|
||||
|
||||
[JsonProperty("status")]
|
||||
public string Status { get; set; }
|
||||
|
||||
[JsonProperty("requested_status")]
|
||||
public string RequestedStatus { get; set; }
|
||||
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonProperty("project_id")]
|
||||
public string ProjectId { get; set; }
|
||||
|
||||
[JsonProperty("author_id")]
|
||||
public string AuthorId { get; set; }
|
||||
|
||||
[JsonProperty("date_published")]
|
||||
public DateTime DatePublished { get; set; }
|
||||
|
||||
[JsonProperty("downloads")]
|
||||
public long Downloads { get; set; }
|
||||
|
||||
[JsonProperty("changelog_url")]
|
||||
public object ChangelogUrl { get; set; }
|
||||
|
||||
[JsonProperty("files")]
|
||||
public VersionFile[] Files { get; set; }
|
||||
}
|
||||
21
Moonlight/App/ApiClients/Modrinth/Resources/VersionFile.cs
Normal file
21
Moonlight/App/ApiClients/Modrinth/Resources/VersionFile.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.ApiClients.Modrinth.Resources;
|
||||
|
||||
public class VersionFile
|
||||
{
|
||||
[JsonProperty("url")]
|
||||
public Uri Url { get; set; }
|
||||
|
||||
[JsonProperty("filename")]
|
||||
public string Filename { get; set; }
|
||||
|
||||
[JsonProperty("primary")]
|
||||
public bool Primary { get; set; }
|
||||
|
||||
[JsonProperty("size")]
|
||||
public long Size { get; set; }
|
||||
|
||||
[JsonProperty("file_type")]
|
||||
public string FileType { get; set; }
|
||||
}
|
||||
11
Moonlight/App/ApiClients/Telemetry/Requests/TelemetryData.cs
Normal file
11
Moonlight/App/ApiClients/Telemetry/Requests/TelemetryData.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Moonlight.App.ApiClients.Telemetry.Requests;
|
||||
|
||||
public class TelemetryData
|
||||
{
|
||||
public string AppUrl { get; set; } = "";
|
||||
public int Servers { get; set; }
|
||||
public int Nodes { get; set; }
|
||||
public int Users { get; set; }
|
||||
public int Databases { get; set; }
|
||||
public int Webspaces { get; set; }
|
||||
}
|
||||
52
Moonlight/App/ApiClients/Telemetry/TelemetryApiHelper.cs
Normal file
52
Moonlight/App/ApiClients/Telemetry/TelemetryApiHelper.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Newtonsoft.Json;
|
||||
using RestSharp;
|
||||
|
||||
namespace Moonlight.App.ApiClients.Telemetry;
|
||||
|
||||
public class TelemetryApiHelper
|
||||
{
|
||||
private readonly RestClient Client;
|
||||
|
||||
public TelemetryApiHelper()
|
||||
{
|
||||
Client = new();
|
||||
}
|
||||
|
||||
public async Task Post(string resource, object? body)
|
||||
{
|
||||
var request = CreateRequest(resource);
|
||||
|
||||
request.Method = Method.Post;
|
||||
|
||||
request.AddParameter("application/json", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
if (response.StatusCode != 0)
|
||||
{
|
||||
throw new TelemetryException(
|
||||
$"An error occured: ({response.StatusCode}) {response.Content}",
|
||||
(int)response.StatusCode
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"An internal error occured: {response.ErrorMessage}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RestRequest CreateRequest(string resource)
|
||||
{
|
||||
var url = "https://telemetry.moonlightpanel.xyz/" + resource;
|
||||
|
||||
var request = new RestRequest(url)
|
||||
{
|
||||
Timeout = 3000000
|
||||
};
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
32
Moonlight/App/ApiClients/Telemetry/TelemetryException.cs
Normal file
32
Moonlight/App/ApiClients/Telemetry/TelemetryException.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Moonlight.App.ApiClients.Telemetry;
|
||||
|
||||
[Serializable]
|
||||
public class TelemetryException : Exception
|
||||
{
|
||||
public int StatusCode { get; set; }
|
||||
|
||||
public TelemetryException()
|
||||
{
|
||||
}
|
||||
|
||||
public TelemetryException(string message, int statusCode) : base(message)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
}
|
||||
|
||||
public TelemetryException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public TelemetryException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
}
|
||||
|
||||
protected TelemetryException(
|
||||
SerializationInfo info,
|
||||
StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ public class WingsApiHelper
|
||||
|
||||
var request = new RestRequest(url)
|
||||
{
|
||||
Timeout = 60 * 15
|
||||
Timeout = 300000
|
||||
};
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
|
||||
369
Moonlight/App/Configuration/ConfigV1.cs
Normal file
369
Moonlight/App/Configuration/ConfigV1.cs
Normal file
@@ -0,0 +1,369 @@
|
||||
using System.ComponentModel;
|
||||
using Moonlight.App.Helpers;
|
||||
|
||||
namespace Moonlight.App.Configuration;
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
public class ConfigV1
|
||||
{
|
||||
[JsonProperty("Moonlight")]
|
||||
public MoonlightData Moonlight { get; set; } = new();
|
||||
|
||||
public class MoonlightData
|
||||
{
|
||||
[JsonProperty("AppUrl")]
|
||||
[Description("The url moonlight is accesible with from the internet")]
|
||||
public string AppUrl { get; set; } = "http://your-moonlight-url-without-slash";
|
||||
|
||||
[JsonProperty("EnableLatencyCheck")]
|
||||
[Description(
|
||||
"This will enable a latency check for connections to moonlight. Users with an too high latency will be warned that moonlight might be buggy for them")]
|
||||
public bool EnableLatencyCheck { get; set; } = true;
|
||||
|
||||
[JsonProperty("LatencyCheckThreshold")]
|
||||
[Description("Specify the latency threshold which has to be reached in order to trigger the warning message")]
|
||||
public int LatencyCheckThreshold { get; set; } = 1000;
|
||||
|
||||
[JsonProperty("Auth")] public AuthData Auth { get; set; } = new();
|
||||
|
||||
[JsonProperty("Database")] public DatabaseData Database { get; set; } = new();
|
||||
|
||||
[JsonProperty("DiscordBotApi")] public DiscordBotApiData DiscordBotApi { get; set; } = new();
|
||||
|
||||
[JsonProperty("DiscordBot")] public DiscordBotData DiscordBot { get; set; } = new();
|
||||
|
||||
[JsonProperty("Domains")] public DomainsData Domains { get; set; } = new();
|
||||
|
||||
[JsonProperty("Html")] public HtmlData Html { get; set; } = new();
|
||||
|
||||
[JsonProperty("Marketing")] public MarketingData Marketing { get; set; } = new();
|
||||
|
||||
[JsonProperty("OAuth2")] public OAuth2Data OAuth2 { get; set; } = new();
|
||||
|
||||
[JsonProperty("Security")] public SecurityData Security { get; set; } = new();
|
||||
|
||||
[JsonProperty("Mail")] public MailData Mail { get; set; } = new();
|
||||
|
||||
[JsonProperty("Cleanup")] public CleanupData Cleanup { get; set; } = new();
|
||||
|
||||
[JsonProperty("DiscordNotifications")] public DiscordNotificationsData DiscordNotifications { get; set; } = new();
|
||||
|
||||
[JsonProperty("Statistics")] public StatisticsData Statistics { get; set; } = new();
|
||||
|
||||
[JsonProperty("Rating")] public RatingData Rating { get; set; } = new();
|
||||
|
||||
[JsonProperty("SmartDeploy")] public SmartDeployData SmartDeploy { get; set; } = new();
|
||||
|
||||
[JsonProperty("Sentry")] public SentryData Sentry { get; set; } = new();
|
||||
|
||||
[JsonProperty("Stripe")] public StripeData Stripe { get; set; } = new();
|
||||
|
||||
[JsonProperty("Tickets")] public TicketsData Tickets { get; set; } = new();
|
||||
}
|
||||
|
||||
public class TicketsData
|
||||
{
|
||||
[JsonProperty("WelcomeMessage")]
|
||||
[Description("The message that will be sent when a user created a ticket")]
|
||||
public string WelcomeMessage { get; set; } = "Welcome to the support";
|
||||
}
|
||||
|
||||
public class StripeData
|
||||
{
|
||||
[JsonProperty("ApiKey")]
|
||||
[Description("Put here your stripe api key if you add subscriptions. Currently the only billing option is stripe which is enabled by default and cannot be turned off. This feature is still experimental")]
|
||||
public string ApiKey { get; set; } = "";
|
||||
}
|
||||
|
||||
public class AuthData
|
||||
{
|
||||
[JsonProperty("DenyLogin")]
|
||||
[Description("Prevent every new login")]
|
||||
public bool DenyLogin { get; set; } = false;
|
||||
|
||||
[JsonProperty("DenyRegister")]
|
||||
[Description("Prevent every new user to register")]
|
||||
public bool DenyRegister { get; set; } = false;
|
||||
}
|
||||
|
||||
public class CleanupData
|
||||
{
|
||||
[JsonProperty("Cpu")]
|
||||
[Description("The maximum amount of cpu usage in percent a node is allowed to use before the cleanup starts")]
|
||||
public long Cpu { get; set; } = 90;
|
||||
|
||||
[JsonProperty("Memory")]
|
||||
[Description("The minumum amount of memory in megabytes avaliable before the cleanup starts")]
|
||||
public long Memory { get; set; } = 8192;
|
||||
|
||||
[JsonProperty("Wait")]
|
||||
[Description("The delay between every cleanup check in minutes")]
|
||||
public long Wait { get; set; } = 15;
|
||||
|
||||
[JsonProperty("Uptime")]
|
||||
[Description("The maximum uptime of any server in hours before it the server restarted by the cleanup system")]
|
||||
public long Uptime { get; set; } = 6;
|
||||
|
||||
[JsonProperty("Enable")]
|
||||
[Description("The cleanup system provides a fair way for stopping unused servers and staying stable even with overallocation. A detailed explanation: docs.endelon-hosting.de/erklaerungen/cleanup")]
|
||||
public bool Enable { get; set; } = false;
|
||||
|
||||
[JsonProperty("MinUptime")]
|
||||
[Description("The minumum uptime of a server in minutes to prevent stopping servers which just started")]
|
||||
public long MinUptime { get; set; } = 10;
|
||||
}
|
||||
|
||||
public class DatabaseData
|
||||
{
|
||||
[JsonProperty("Database")] public string Database { get; set; } = "moonlight_db";
|
||||
|
||||
[JsonProperty("Host")] public string Host { get; set; } = "your.database.host";
|
||||
|
||||
[JsonProperty("Password")]
|
||||
[Blur]
|
||||
public string Password { get; set; } = "secret";
|
||||
|
||||
[JsonProperty("Port")] public long Port { get; set; } = 3306;
|
||||
|
||||
[JsonProperty("Username")] public string Username { get; set; } = "moonlight_user";
|
||||
}
|
||||
|
||||
public class DiscordBotApiData
|
||||
{
|
||||
[JsonProperty("Enable")]
|
||||
[Description("Enable the discord bot api. Currently only DatBot is using this api")]
|
||||
public bool Enable { get; set; } = false;
|
||||
|
||||
[JsonProperty("Token")]
|
||||
[Description("Specify the token the api client needs to provide")]
|
||||
[Blur]
|
||||
public string Token { get; set; } = Guid.NewGuid().ToString();
|
||||
}
|
||||
public class DiscordBotData
|
||||
{
|
||||
[JsonProperty("Enable")]
|
||||
[Description("The discord bot can be used to allow customers to manage their servers via discord")]
|
||||
public bool Enable { get; set; } = false;
|
||||
|
||||
[JsonProperty("Token")]
|
||||
[Description("Your discord bot token goes here")]
|
||||
[Blur]
|
||||
public string Token { get; set; } = "discord token here";
|
||||
|
||||
[JsonProperty("PowerActions")]
|
||||
[Description("Enable actions like starting and stopping servers")]
|
||||
public bool PowerActions { get; set; } = false;
|
||||
|
||||
[JsonProperty("SendCommands")]
|
||||
[Description("Allow users to send commands to their servers")]
|
||||
public bool SendCommands { get; set; } = false;
|
||||
}
|
||||
|
||||
public class DiscordNotificationsData
|
||||
{
|
||||
[JsonProperty("Enable")]
|
||||
[Description("The discord notification system sends you a message everytime a event like a new support chat message is triggered with usefull data describing the event")]
|
||||
public bool Enable { get; set; } = false;
|
||||
|
||||
[JsonProperty("WebHook")]
|
||||
[Description("The discord webhook the notifications are being sent to")]
|
||||
[Blur]
|
||||
public string WebHook { get; set; } = "http://your-discord-webhook-url";
|
||||
}
|
||||
|
||||
public class DomainsData
|
||||
{
|
||||
[JsonProperty("Enable")]
|
||||
[Description("This enables the domain system")]
|
||||
public bool Enable { get; set; } = false;
|
||||
|
||||
[JsonProperty("AccountId")]
|
||||
[Description("This option specifies the cloudflare account id")]
|
||||
public string AccountId { get; set; } = "cloudflare acc id";
|
||||
|
||||
[JsonProperty("Email")]
|
||||
[Description("This specifies the cloudflare email to use for communicating with the cloudflare api")]
|
||||
public string Email { get; set; } = "cloudflare@acc.email";
|
||||
|
||||
[JsonProperty("Key")]
|
||||
[Description("Your cloudflare api key goes here")]
|
||||
[Blur]
|
||||
public string Key { get; set; } = "secret";
|
||||
}
|
||||
|
||||
public class HtmlData
|
||||
{
|
||||
[JsonProperty("Headers")] public HeadersData Headers { get; set; } = new();
|
||||
}
|
||||
|
||||
public class HeadersData
|
||||
{
|
||||
[JsonProperty("Color")]
|
||||
[Description("This specifies the color of the embed generated by platforms like discord when someone posts a link to your moonlight instance")]
|
||||
public string Color { get; set; } = "#4b27e8";
|
||||
|
||||
[JsonProperty("Description")]
|
||||
[Description("This specifies the description text of the embed generated by platforms like discord when someone posts a link to your moonlight instance and can also help google to index your moonlight instance correctly")]
|
||||
public string Description { get; set; } = "the next generation hosting panel";
|
||||
|
||||
[JsonProperty("Keywords")]
|
||||
[Description("To help search engines like google to index your moonlight instance correctly you can specify keywords seperated by a comma here")]
|
||||
public string Keywords { get; set; } = "moonlight";
|
||||
|
||||
[JsonProperty("Title")]
|
||||
[Description("This specifies the title of the embed generated by platforms like discord when someone posts a link to your moonlight instance")]
|
||||
public string Title { get; set; } = "Moonlight - endelon.link";
|
||||
}
|
||||
|
||||
public class MailData
|
||||
{
|
||||
[JsonProperty("Email")] public string Email { get; set; } = "username@your.mail.host";
|
||||
|
||||
[JsonProperty("Server")] public string Server { get; set; } = "your.mail.host";
|
||||
|
||||
[JsonProperty("Password")]
|
||||
[Blur]
|
||||
public string Password { get; set; } = "secret";
|
||||
|
||||
[JsonProperty("Port")] public int Port { get; set; } = 465;
|
||||
|
||||
[JsonProperty("Ssl")] public bool Ssl { get; set; } = true;
|
||||
}
|
||||
|
||||
public class MarketingData
|
||||
{
|
||||
[JsonProperty("BrandName")] public string BrandName { get; set; } = "Endelon Hosting";
|
||||
|
||||
[JsonProperty("Imprint")] public string Imprint { get; set; } = "https://your-site.xyz/imprint";
|
||||
|
||||
[JsonProperty("Privacy")] public string Privacy { get; set; } = "https://your-site.xyz/privacy";
|
||||
[JsonProperty("About")] public string About { get; set; } = "https://your-site.xyz/about";
|
||||
[JsonProperty("Website")] public string Website { get; set; } = "https://your-site.xyz";
|
||||
}
|
||||
|
||||
public class OAuth2Data
|
||||
{
|
||||
[JsonProperty("OverrideUrl")]
|
||||
[Description("This overrides the redirect url which would be typicaly the app url")]
|
||||
public string OverrideUrl { get; set; } = "https://only-for-development.cases";
|
||||
|
||||
[JsonProperty("EnableOverrideUrl")]
|
||||
[Description("This enables the url override")]
|
||||
public bool EnableOverrideUrl { get; set; } = false;
|
||||
|
||||
[JsonProperty("Providers")]
|
||||
public OAuth2ProviderData[] Providers { get; set; } = Array.Empty<OAuth2ProviderData>();
|
||||
}
|
||||
|
||||
public class OAuth2ProviderData
|
||||
{
|
||||
[JsonProperty("Id")] public string Id { get; set; }
|
||||
|
||||
[JsonProperty("ClientId")] public string ClientId { get; set; }
|
||||
|
||||
[JsonProperty("ClientSecret")]
|
||||
[Blur]
|
||||
public string ClientSecret { get; set; }
|
||||
}
|
||||
|
||||
public class RatingData
|
||||
{
|
||||
[JsonProperty("Enabled")]
|
||||
[Description("The rating systems shows a user who is registered longer than the set amout of days a popup to rate this platform if he hasnt rated it before")]
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
[JsonProperty("Url")]
|
||||
[Description("This is the url a user who rated above a set limit is shown to rate you again. Its recommended to put your google or trustpilot rate link here")]
|
||||
public string Url { get; set; } = "https://link-to-google-or-smth";
|
||||
|
||||
[JsonProperty("MinRating")]
|
||||
[Description("The minimum star count on the rating ranging from 1 to 5")]
|
||||
public int MinRating { get; set; } = 4;
|
||||
|
||||
[JsonProperty("DaysSince")]
|
||||
[Description("The days a user has to be registered to even be able to get this popup")]
|
||||
public int DaysSince { get; set; } = 5;
|
||||
}
|
||||
|
||||
public class SecurityData
|
||||
{
|
||||
[JsonProperty("Token")]
|
||||
[Description("This is the moonlight app token. It is used to encrypt and decrypt data and validate tokens and sessions")]
|
||||
[Blur]
|
||||
public string Token { get; set; } = Guid.NewGuid().ToString();
|
||||
|
||||
[JsonProperty("MalwareCheckOnStart")]
|
||||
[Description(
|
||||
"This option will enable the scanning for malware on every server before it has been started and if something has been found, the power action will be canceled")]
|
||||
public bool MalwareCheckOnStart { get; set; } = true;
|
||||
|
||||
[JsonProperty("BlockIpDuration")]
|
||||
[Description("The duration in minutes a ip will be blocked by the anti ddos system")]
|
||||
public int BlockIpDuration { get; set; } = 15;
|
||||
|
||||
[JsonProperty("ReCaptcha")] public ReCaptchaData ReCaptcha { get; set; } = new();
|
||||
|
||||
[JsonProperty("BlockDatacenterIps")]
|
||||
[Description("If this option is enabled, users with an ip from datacenters will not be able to access the panel")]
|
||||
public bool BlockDatacenterIps { get; set; } = true;
|
||||
|
||||
[JsonProperty("AllowCloudflareIps")]
|
||||
[Description("Allow cloudflare ips to bypass the datacenter ip check")]
|
||||
public bool AllowCloudflareIps { get; set; } = false;
|
||||
}
|
||||
|
||||
public class ReCaptchaData
|
||||
{
|
||||
[JsonProperty("Enable")]
|
||||
[Description("Enables repatcha at places like the register page. For information how to get your recaptcha credentails go to google.com/recaptcha/about/")]
|
||||
public bool Enable { get; set; } = false;
|
||||
|
||||
[JsonProperty("SiteKey")]
|
||||
[Blur]
|
||||
public string SiteKey { get; set; } = "recaptcha site key here";
|
||||
|
||||
[JsonProperty("SecretKey")]
|
||||
[Blur]
|
||||
public string SecretKey { get; set; } = "recaptcha secret here";
|
||||
}
|
||||
|
||||
public class SentryData
|
||||
{
|
||||
[JsonProperty("Enable")]
|
||||
[Description("Sentry is a way to monitor application crashes and performance issues in real time. Enable this option only if you set a sentry dsn")]
|
||||
public bool Enable { get; set; } = false;
|
||||
|
||||
[JsonProperty("Dsn")]
|
||||
[Description("The dsn is the key moonlight needs to communicate with your sentry instance")]
|
||||
[Blur]
|
||||
public string Dsn { get; set; } = "http://your-sentry-url-here";
|
||||
}
|
||||
|
||||
public class SmartDeployData
|
||||
{
|
||||
[JsonProperty("Server")] public SmartDeployServerData Server { get; set; } = new();
|
||||
}
|
||||
|
||||
public class SmartDeployServerData
|
||||
{
|
||||
[JsonProperty("EnableOverride")] public bool EnableOverride { get; set; } = false;
|
||||
|
||||
[JsonProperty("OverrideNode")] public long OverrideNode { get; set; } = 1;
|
||||
}
|
||||
|
||||
public class StatisticsData
|
||||
{
|
||||
[JsonProperty("Enabled")] public bool Enabled { get; set; } = false;
|
||||
|
||||
[JsonProperty("Wait")] public long Wait { get; set; } = 15;
|
||||
}
|
||||
|
||||
public class SellPassData
|
||||
{
|
||||
[JsonProperty("Enable")] public bool Enable { get; set; } = false;
|
||||
|
||||
[JsonProperty("Url")] public string Url { get; set; } = "https://not-implemented-yet";
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Database.Entities.LogsEntries;
|
||||
using Moonlight.App.Database.Entities.Notification;
|
||||
using Moonlight.App.Database.Interceptors;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.Database;
|
||||
@@ -27,10 +25,6 @@ public class DataContext : DbContext
|
||||
public DbSet<ServerVariable> ServerVariables { get; set; }
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<LoadingMessage> LoadingMessages { get; set; }
|
||||
public DbSet<AuditLogEntry> AuditLog { get; set; }
|
||||
public DbSet<ErrorLogEntry> ErrorLog { get; set; }
|
||||
public DbSet<SecurityLogEntry> SecurityLog { get; set; }
|
||||
|
||||
public DbSet<SharedDomain> SharedDomains { get; set; }
|
||||
public DbSet<Domain> Domains { get; set; }
|
||||
public DbSet<Revoke> Revokes { get; set; }
|
||||
@@ -46,20 +40,27 @@ public class DataContext : DbContext
|
||||
public DbSet<WebSpace> WebSpaces { get; set; }
|
||||
public DbSet<SupportChatMessage> SupportChatMessages { get; set; }
|
||||
public DbSet<IpBan> IpBans { get; set; }
|
||||
public DbSet<PermissionGroup> PermissionGroups { get; set; }
|
||||
public DbSet<SecurityLog> SecurityLogs { get; set; }
|
||||
public DbSet<BlocklistIp> BlocklistIps { get; set; }
|
||||
public DbSet<WhitelistIp> WhitelistIps { get; set; }
|
||||
|
||||
public DbSet<Ticket> Tickets { get; set; }
|
||||
public DbSet<TicketMessage> TicketMessages { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
if (!optionsBuilder.IsConfigured)
|
||||
{
|
||||
var config = ConfigService
|
||||
.GetSection("Moonlight")
|
||||
.GetSection("Database");
|
||||
.Get()
|
||||
.Moonlight.Database;
|
||||
|
||||
var connectionString = $"host={config.GetValue<string>("Host")};" +
|
||||
$"port={config.GetValue<int>("Port")};" +
|
||||
$"database={config.GetValue<string>("Database")};" +
|
||||
$"uid={config.GetValue<string>("Username")};" +
|
||||
$"pwd={config.GetValue<string>("Password")}";
|
||||
var connectionString = $"host={config.Host};" +
|
||||
$"port={config.Port};" +
|
||||
$"database={config.Database};" +
|
||||
$"uid={config.Username};" +
|
||||
$"pwd={config.Password}";
|
||||
|
||||
optionsBuilder.UseMySql(
|
||||
connectionString,
|
||||
|
||||
10
Moonlight/App/Database/Entities/BlocklistIp.cs
Normal file
10
Moonlight/App/Database/Entities/BlocklistIp.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class BlocklistIp
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Ip { get; set; } = "";
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
public long Packets { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using Moonlight.App.Models.Misc;
|
||||
|
||||
namespace Moonlight.App.Database.Entities.LogsEntries;
|
||||
|
||||
public class AuditLogEntry
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public AuditLogType Type { get; set; }
|
||||
public string JsonData { get; set; } = "";
|
||||
public bool System { get; set; }
|
||||
public string Ip { get; set; } = "";
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace Moonlight.App.Database.Entities.LogsEntries;
|
||||
|
||||
public class ErrorLogEntry
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Stacktrace { get; set; } = "";
|
||||
public bool System { get; set; }
|
||||
public string JsonData { get; set; } = "";
|
||||
public string Ip { get; set; } = "";
|
||||
public string Class { get; set; } = "";
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using Moonlight.App.Models.Misc;
|
||||
|
||||
namespace Moonlight.App.Database.Entities.LogsEntries;
|
||||
|
||||
public class SecurityLogEntry
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public bool System { get; set; }
|
||||
public string Ip { get; set; } = "";
|
||||
public SecurityLogType Type { get; set; }
|
||||
public string JsonData { get; set; } = "";
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
8
Moonlight/App/Database/Entities/PermissionGroup.cs
Normal file
8
Moonlight/App/Database/Entities/PermissionGroup.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class PermissionGroup
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = "";
|
||||
public byte[] Permissions { get; set; } = Array.Empty<byte>();
|
||||
}
|
||||
8
Moonlight/App/Database/Entities/SecurityLog.cs
Normal file
8
Moonlight/App/Database/Entities/SecurityLog.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class SecurityLog
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Text { get; set; } = "";
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -13,6 +13,8 @@ public class Server
|
||||
public string OverrideStartup { get; set; } = "";
|
||||
public bool Installing { get; set; } = false;
|
||||
public bool Suspended { get; set; } = false;
|
||||
public bool IsArchived { get; set; } = false;
|
||||
public ServerBackup? Archive { get; set; } = null;
|
||||
|
||||
public List<ServerVariable> Variables { get; set; } = new();
|
||||
public List<ServerBackup> Backups { get; set; } = new();
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class Subscription
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public Currency Currency { get; set; } = Currency.USD;
|
||||
public double Price { get; set; }
|
||||
public string StripeProductId { get; set; } = "";
|
||||
public string StripePriceId { get; set; } = "";
|
||||
public string LimitsJson { get; set; } = "";
|
||||
public int Duration { get; set; } = 30;
|
||||
}
|
||||
19
Moonlight/App/Database/Entities/Ticket.cs
Normal file
19
Moonlight/App/Database/Entities/Ticket.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Moonlight.App.Models.Misc;
|
||||
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class Ticket
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string IssueTopic { get; set; } = "";
|
||||
public string IssueDescription { get; set; } = "";
|
||||
public string IssueTries { get; set; } = "";
|
||||
public User CreatedBy { get; set; }
|
||||
public User? AssignedTo { get; set; }
|
||||
public TicketPriority Priority { get; set; }
|
||||
public TicketStatus Status { get; set; }
|
||||
public TicketSubject Subject { get; set; }
|
||||
public int SubjectId { get; set; }
|
||||
public List<TicketMessage> Messages { get; set; } = new();
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
14
Moonlight/App/Database/Entities/TicketMessage.cs
Normal file
14
Moonlight/App/Database/Entities/TicketMessage.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class TicketMessage
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Content { get; set; } = "";
|
||||
public string? AttachmentUrl { get; set; }
|
||||
public User? Sender { get; set; }
|
||||
public bool IsSystemMessage { get; set; }
|
||||
public bool IsEdited { get; set; }
|
||||
public bool IsSupportMessage { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Moonlight.App.Models.Misc;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Moonlight.App.Models.Misc;
|
||||
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
@@ -23,7 +24,9 @@ public class User
|
||||
public string State { get; set; } = "";
|
||||
|
||||
public string Country { get; set; } = "";
|
||||
|
||||
|
||||
public string ServerListLayoutJson { get; set; } = "";
|
||||
|
||||
// States
|
||||
|
||||
public UserStatus Status { get; set; } = UserStatus.Unverified;
|
||||
@@ -31,11 +34,14 @@ public class User
|
||||
public bool SupportPending { get; set; } = false;
|
||||
public bool HasRated { get; set; } = false;
|
||||
public int Rating { get; set; } = 0;
|
||||
public bool StreamerMode { get; set; } = false;
|
||||
|
||||
// Security
|
||||
public bool TotpEnabled { get; set; } = false;
|
||||
public string TotpSecret { get; set; } = "";
|
||||
public DateTime TokenValidTime { get; set; } = DateTime.UtcNow;
|
||||
public byte[] Permissions { get; set; } = Array.Empty<byte>();
|
||||
public PermissionGroup? PermissionGroup { get; set; }
|
||||
|
||||
// Discord
|
||||
public ulong DiscordId { get; set; }
|
||||
@@ -48,6 +54,10 @@ public class User
|
||||
// Subscriptions
|
||||
|
||||
public Subscription? CurrentSubscription { get; set; } = null;
|
||||
public DateTime SubscriptionSince { get; set; } = DateTime.Now;
|
||||
public int SubscriptionDuration { get; set; }
|
||||
public DateTime SubscriptionSince { get; set; } = DateTime.UtcNow;
|
||||
public DateTime SubscriptionExpires { get; set; } = DateTime.UtcNow;
|
||||
|
||||
// Ip logs
|
||||
public string RegisterIp { get; set; } = "";
|
||||
public string LastIp { get; set; } = "";
|
||||
}
|
||||
7
Moonlight/App/Database/Entities/WhitelistIp.cs
Normal file
7
Moonlight/App/Database/Entities/WhitelistIp.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class WhitelistIp
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Ip { get; set; } = "";
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Data.Common;
|
||||
using Logging.Net;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Moonlight.App.Helpers;
|
||||
|
||||
namespace Moonlight.App.Database.Interceptors;
|
||||
|
||||
|
||||
1073
Moonlight/App/Database/Migrations/20230614010621_AddedServerAchive.Designer.cs
generated
Normal file
1073
Moonlight/App/Database/Migrations/20230614010621_AddedServerAchive.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedServerAchive : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "ArchiveId",
|
||||
table: "Servers",
|
||||
type: "int",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "IsArchived",
|
||||
table: "Servers",
|
||||
type: "tinyint(1)",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Servers_ArchiveId",
|
||||
table: "Servers",
|
||||
column: "ArchiveId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Servers_ServerBackups_ArchiveId",
|
||||
table: "Servers",
|
||||
column: "ArchiveId",
|
||||
principalTable: "ServerBackups",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Servers_ServerBackups_ArchiveId",
|
||||
table: "Servers");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Servers_ArchiveId",
|
||||
table: "Servers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ArchiveId",
|
||||
table: "Servers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IsArchived",
|
||||
table: "Servers");
|
||||
}
|
||||
}
|
||||
}
|
||||
1077
Moonlight/App/Database/Migrations/20230623235512_AddedServerListLayoutToUser.Designer.cs
generated
Normal file
1077
Moonlight/App/Database/Migrations/20230623235512_AddedServerListLayoutToUser.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedServerListLayoutToUser : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "ServerListLayoutJson",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ServerListLayoutJson",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
||||
1080
Moonlight/App/Database/Migrations/20230625190428_AddedStreamerMode.Designer.cs
generated
Normal file
1080
Moonlight/App/Database/Migrations/20230625190428_AddedStreamerMode.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedStreamerMode : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "StreamerMode",
|
||||
table: "Users",
|
||||
type: "tinyint(1)",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StreamerMode",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
||||
1088
Moonlight/App/Database/Migrations/20230703175432_AddedIpLogsForUser.Designer.cs
generated
Normal file
1088
Moonlight/App/Database/Migrations/20230703175432_AddedIpLogsForUser.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedIpLogsForUser : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "LastIp",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "RegisterIp",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "LastIp",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "RegisterIp",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
||||
1105
Moonlight/App/Database/Migrations/20230705171914_AddedStripeIntegration.Designer.cs
generated
Normal file
1105
Moonlight/App/Database/Migrations/20230705171914_AddedStripeIntegration.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedStripeIntegration : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SubscriptionDuration",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "SubscriptionExpires",
|
||||
table: "Users",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Currency",
|
||||
table: "Subscriptions",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Duration",
|
||||
table: "Subscriptions",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "Price",
|
||||
table: "Subscriptions",
|
||||
type: "double",
|
||||
nullable: false,
|
||||
defaultValue: 0.0);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "StripePriceId",
|
||||
table: "Subscriptions",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "StripeProductId",
|
||||
table: "Subscriptions",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SubscriptionExpires",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Currency",
|
||||
table: "Subscriptions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Duration",
|
||||
table: "Subscriptions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Price",
|
||||
table: "Subscriptions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StripePriceId",
|
||||
table: "Subscriptions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StripeProductId",
|
||||
table: "Subscriptions");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "SubscriptionDuration",
|
||||
table: "Users",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
1109
Moonlight/App/Database/Migrations/20230715095531_AddPermissions.Designer.cs
generated
Normal file
1109
Moonlight/App/Database/Migrations/20230715095531_AddPermissions.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddPermissions : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<byte[]>(
|
||||
name: "Permissions",
|
||||
table: "Users",
|
||||
type: "longblob",
|
||||
nullable: false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Permissions",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
||||
1139
Moonlight/App/Database/Migrations/20230715214550_AddPermissionGroup.Designer.cs
generated
Normal file
1139
Moonlight/App/Database/Migrations/20230715214550_AddPermissionGroup.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddPermissionGroup : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "PermissionGroupId",
|
||||
table: "Users",
|
||||
type: "int",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PermissionGroups",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Name = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Permissions = table.Column<byte[]>(type: "longblob", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PermissionGroups", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Users_PermissionGroupId",
|
||||
table: "Users",
|
||||
column: "PermissionGroupId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Users_PermissionGroups_PermissionGroupId",
|
||||
table: "Users",
|
||||
column: "PermissionGroupId",
|
||||
principalTable: "PermissionGroups",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Users_PermissionGroups_PermissionGroupId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PermissionGroups");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Users_PermissionGroupId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PermissionGroupId",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
||||
1068
Moonlight/App/Database/Migrations/20230718123232_RemovedOldLogsAndAddedErrorLog.Designer.cs
generated
Normal file
1068
Moonlight/App/Database/Migrations/20230718123232_RemovedOldLogsAndAddedErrorLog.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RemovedOldLogsAndAddedErrorLog : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AuditLog");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ErrorLog");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "SecurityLog");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SecurityLogs",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Text = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SecurityLogs", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "SecurityLogs");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AuditLog",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
JsonData = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
System = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
Type = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AuditLog", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ErrorLog",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Class = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
JsonData = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Stacktrace = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
System = table.Column<bool>(type: "tinyint(1)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ErrorLog", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SecurityLog",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
JsonData = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
System = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
Type = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SecurityLog", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
}
|
||||
}
|
||||
1107
Moonlight/App/Database/Migrations/20230721201950_AddIpRules.Designer.cs
generated
Normal file
1107
Moonlight/App/Database/Migrations/20230721201950_AddIpRules.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddIpRules : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "BlocklistIps",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
ExpiresAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
Packets = table.Column<long>(type: "bigint", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_BlocklistIps", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "WhitelistIps",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_WhitelistIps", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "BlocklistIps");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "WhitelistIps");
|
||||
}
|
||||
}
|
||||
}
|
||||
1233
Moonlight/App/Database/Migrations/20230803012947_AddNewTicketModels.Designer.cs
generated
Normal file
1233
Moonlight/App/Database/Migrations/20230803012947_AddNewTicketModels.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddNewTicketModels : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Tickets",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
IssueTopic = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
IssueDescription = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
IssueTries = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
CreatedById = table.Column<int>(type: "int", nullable: false),
|
||||
AssignedToId = table.Column<int>(type: "int", nullable: true),
|
||||
Priority = table.Column<int>(type: "int", nullable: false),
|
||||
Status = table.Column<int>(type: "int", nullable: false),
|
||||
Subject = table.Column<int>(type: "int", nullable: false),
|
||||
SubjectId = table.Column<int>(type: "int", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Tickets", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Tickets_Users_AssignedToId",
|
||||
column: x => x.AssignedToId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Tickets_Users_CreatedById",
|
||||
column: x => x.CreatedById,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "TicketMessages",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Content = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
AttachmentUrl = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
SenderId = table.Column<int>(type: "int", nullable: true),
|
||||
IsSystemMessage = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
IsEdited = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
IsSupportMessage = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
TicketId = table.Column<int>(type: "int", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_TicketMessages", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_TicketMessages_Tickets_TicketId",
|
||||
column: x => x.TicketId,
|
||||
principalTable: "Tickets",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_TicketMessages_Users_SenderId",
|
||||
column: x => x.SenderId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id");
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_TicketMessages_SenderId",
|
||||
table: "TicketMessages",
|
||||
column: "SenderId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_TicketMessages_TicketId",
|
||||
table: "TicketMessages",
|
||||
column: "TicketId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Tickets_AssignedToId",
|
||||
table: "Tickets",
|
||||
column: "AssignedToId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Tickets_CreatedById",
|
||||
table: "Tickets",
|
||||
column: "CreatedById");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "TicketMessages");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Tickets");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,30 @@ namespace Moonlight.App.Database.Migrations
|
||||
.HasAnnotation("ProductVersion", "7.0.3")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.BlocklistIp", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Ip")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("Packets")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("BlocklistIps");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.CloudPanel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -241,95 +265,6 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.ToTable("LoadingMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.AuditLogEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Ip")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("JsonData")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("System")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AuditLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.ErrorLogEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Class")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Ip")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("JsonData")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Stacktrace")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("System")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ErrorLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.SecurityLogEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Ip")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("JsonData")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("System")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SecurityLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.MySqlDatabase", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -475,6 +410,25 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.ToTable("NotificationClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.PermissionGroup", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<byte[]>("Permissions")
|
||||
.IsRequired()
|
||||
.HasColumnType("longblob");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PermissionGroups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Revoke", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -490,12 +444,33 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.ToTable("Revokes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.SecurityLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SecurityLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ArchiveId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Cpu")
|
||||
.HasColumnType("int");
|
||||
|
||||
@@ -511,6 +486,9 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.Property<bool>("Installing")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<bool>("IsArchived")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<bool>("IsCleanupException")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
@@ -542,6 +520,8 @@ namespace Moonlight.App.Database.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ArchiveId");
|
||||
|
||||
b.HasIndex("ImageId");
|
||||
|
||||
b.HasIndex("MainAllocationId");
|
||||
@@ -655,10 +635,16 @@ namespace Moonlight.App.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Currency")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Duration")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("LimitsJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
@@ -667,6 +653,17 @@ namespace Moonlight.App.Database.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<double>("Price")
|
||||
.HasColumnType("double");
|
||||
|
||||
b.Property<string>("StripePriceId")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("StripeProductId")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Subscriptions");
|
||||
@@ -717,6 +714,97 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.ToTable("SupportChatMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Ticket", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("AssignedToId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<int>("CreatedById")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("IssueDescription")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("IssueTopic")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("IssueTries")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Subject")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SubjectId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AssignedToId");
|
||||
|
||||
b.HasIndex("CreatedById");
|
||||
|
||||
b.ToTable("Tickets");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.TicketMessage", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("AttachmentUrl")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<bool>("IsEdited")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<bool>("IsSupportMessage")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<bool>("IsSystemMessage")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int?>("SenderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("TicketId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SenderId");
|
||||
|
||||
b.HasIndex("TicketId");
|
||||
|
||||
b.ToTable("TicketMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -758,6 +846,10 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.Property<bool>("HasRated")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("LastIp")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("LastName")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
@@ -769,9 +861,24 @@ namespace Moonlight.App.Database.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("PermissionGroupId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<byte[]>("Permissions")
|
||||
.IsRequired()
|
||||
.HasColumnType("longblob");
|
||||
|
||||
b.Property<int>("Rating")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("RegisterIp")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ServerListLayoutJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("State")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
@@ -779,8 +886,11 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SubscriptionDuration")
|
||||
.HasColumnType("int");
|
||||
b.Property<bool>("StreamerMode")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTime>("SubscriptionExpires")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<DateTime>("SubscriptionSince")
|
||||
.HasColumnType("datetime(6)");
|
||||
@@ -805,6 +915,8 @@ namespace Moonlight.App.Database.Migrations
|
||||
|
||||
b.HasIndex("CurrentSubscriptionId");
|
||||
|
||||
b.HasIndex("PermissionGroupId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
@@ -845,6 +957,21 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.ToTable("WebSpaces");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.WhitelistIp", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Ip")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("WhitelistIps");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.DdosAttack", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Node", "Node")
|
||||
@@ -935,6 +1062,10 @@ namespace Moonlight.App.Database.Migrations
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.ServerBackup", "Archive")
|
||||
.WithMany()
|
||||
.HasForeignKey("ArchiveId");
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
|
||||
.WithMany()
|
||||
.HasForeignKey("ImageId")
|
||||
@@ -957,6 +1088,8 @@ namespace Moonlight.App.Database.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Archive");
|
||||
|
||||
b.Navigation("Image");
|
||||
|
||||
b.Navigation("MainAllocation");
|
||||
@@ -997,13 +1130,49 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.Navigation("Sender");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Ticket", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "AssignedTo")
|
||||
.WithMany()
|
||||
.HasForeignKey("AssignedToId");
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "CreatedBy")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedById")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AssignedTo");
|
||||
|
||||
b.Navigation("CreatedBy");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.TicketMessage", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Sender")
|
||||
.WithMany()
|
||||
.HasForeignKey("SenderId");
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.Ticket", null)
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("TicketId");
|
||||
|
||||
b.Navigation("Sender");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Subscription", "CurrentSubscription")
|
||||
.WithMany()
|
||||
.HasForeignKey("CurrentSubscriptionId");
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.PermissionGroup", "PermissionGroup")
|
||||
.WithMany()
|
||||
.HasForeignKey("PermissionGroupId");
|
||||
|
||||
b.Navigation("CurrentSubscription");
|
||||
|
||||
b.Navigation("PermissionGroup");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b =>
|
||||
@@ -1046,6 +1215,11 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.Navigation("Variables");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Ticket", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b =>
|
||||
{
|
||||
b.Navigation("Databases");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using Logging.Net;
|
||||
using Moonlight.App.Helpers;
|
||||
|
||||
namespace Moonlight.App.Events;
|
||||
|
||||
@@ -112,4 +112,22 @@ public class EventSystem
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<T> WaitForEvent<T>(string id, object handle, Func<T, bool> filter)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<T>();
|
||||
|
||||
Func<T, Task> action = async data =>
|
||||
{
|
||||
if (filter.Invoke(data))
|
||||
{
|
||||
taskCompletionSource.SetResult(data);
|
||||
await Off(id, handle);
|
||||
}
|
||||
};
|
||||
|
||||
On<T>(id, handle, action);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ namespace Moonlight.App.Exceptions;
|
||||
[Serializable]
|
||||
public class DisplayException : Exception
|
||||
{
|
||||
public bool DoNotTranslate { get; set; } = false;
|
||||
|
||||
//
|
||||
// For guidelines regarding the creation of new exception types, see
|
||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
|
||||
@@ -19,6 +21,11 @@ public class DisplayException : Exception
|
||||
public DisplayException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public DisplayException(string message, bool doNotTranslate) : base(message)
|
||||
{
|
||||
DoNotTranslate = doNotTranslate;
|
||||
}
|
||||
|
||||
public DisplayException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
|
||||
30
Moonlight/App/Extensions/JSRuntimeExtensions.cs
Normal file
30
Moonlight/App/Extensions/JSRuntimeExtensions.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Moonlight.App.Extensions;
|
||||
|
||||
public static class JSRuntimeExtensions
|
||||
{
|
||||
public static async Task InvokeVoidSafeAsync(this IJSRuntime jsRuntime, string method, params object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
await jsRuntime.InvokeVoidAsync(method, args);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public static void InvokeVoidSafe(this IJSRuntime jsRuntime, string method, params object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
jsRuntime.InvokeVoidAsync(method, args);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
119
Moonlight/App/Helpers/BackupHelper.cs
Normal file
119
Moonlight/App/Helpers/BackupHelper.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moonlight.App.Database;
|
||||
using Moonlight.App.Services;
|
||||
using MySql.Data.MySqlClient;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class BackupHelper
|
||||
{
|
||||
public async Task CreateBackup(string path)
|
||||
{
|
||||
Logger.Info("Started moonlight backup creation");
|
||||
Logger.Info($"This backup will be saved to '{path}'");
|
||||
|
||||
var stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
|
||||
var cachePath = PathBuilder.Dir("storage", "backups", "cache");
|
||||
|
||||
Directory.CreateDirectory(cachePath);
|
||||
|
||||
//
|
||||
// Exporting database
|
||||
//
|
||||
|
||||
Logger.Info("Exporting database");
|
||||
|
||||
var configService = new ConfigService(new());
|
||||
var dataContext = new DataContext(configService);
|
||||
|
||||
await using MySqlConnection conn = new MySqlConnection(dataContext.Database.GetConnectionString());
|
||||
await using MySqlCommand cmd = new MySqlCommand();
|
||||
using MySqlBackup mb = new MySqlBackup(cmd);
|
||||
|
||||
cmd.Connection = conn;
|
||||
await conn.OpenAsync();
|
||||
mb.ExportToFile(PathBuilder.File(cachePath, "database.sql"));
|
||||
await conn.CloseAsync();
|
||||
|
||||
//
|
||||
// Saving config
|
||||
//
|
||||
|
||||
Logger.Info("Saving configuration");
|
||||
File.Copy(
|
||||
PathBuilder.File("storage", "configs", "config.json"),
|
||||
PathBuilder.File(cachePath, "config.json"));
|
||||
|
||||
//
|
||||
// Saving all storage items needed to restore the panel
|
||||
//
|
||||
|
||||
Logger.Info("Saving resources");
|
||||
CopyDirectory(
|
||||
PathBuilder.Dir("storage", "resources"),
|
||||
PathBuilder.Dir(cachePath, "resources"));
|
||||
|
||||
Logger.Info("Saving logs");
|
||||
CopyDirectory(
|
||||
PathBuilder.Dir("storage", "logs"),
|
||||
PathBuilder.Dir(cachePath, "logs"));
|
||||
|
||||
Logger.Info("Saving uploads");
|
||||
CopyDirectory(
|
||||
PathBuilder.Dir("storage", "uploads"),
|
||||
PathBuilder.Dir(cachePath, "uploads"));
|
||||
|
||||
//
|
||||
// Compressing the backup to a single file
|
||||
//
|
||||
|
||||
Logger.Info("Compressing");
|
||||
ZipFile.CreateFromDirectory(cachePath,
|
||||
path,
|
||||
CompressionLevel.Fastest,
|
||||
false);
|
||||
|
||||
Directory.Delete(cachePath, true);
|
||||
|
||||
stopWatch.Stop();
|
||||
Logger.Info($"Backup successfully created. Took {stopWatch.Elapsed.TotalSeconds} seconds");
|
||||
}
|
||||
|
||||
private void CopyDirectory(string sourceDirName, string destDirName, bool copySubDirs = true)
|
||||
{
|
||||
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
throw new DirectoryNotFoundException($"Source directory does not exist or could not be found: {sourceDirName}");
|
||||
}
|
||||
|
||||
if (!Directory.Exists(destDirName))
|
||||
{
|
||||
Directory.CreateDirectory(destDirName);
|
||||
}
|
||||
|
||||
FileInfo[] files = dir.GetFiles();
|
||||
|
||||
foreach (FileInfo file in files)
|
||||
{
|
||||
string tempPath = Path.Combine(destDirName, file.Name);
|
||||
file.CopyTo(tempPath, false);
|
||||
}
|
||||
|
||||
if (copySubDirs)
|
||||
{
|
||||
DirectoryInfo[] dirs = dir.GetDirectories();
|
||||
|
||||
foreach (DirectoryInfo subdir in dirs)
|
||||
{
|
||||
string tempPath = Path.Combine(destDirName, subdir.Name);
|
||||
CopyDirectory(subdir.FullName, tempPath, copySubDirs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Moonlight/App/Helpers/BitHelper.cs
Normal file
88
Moonlight/App/Helpers/BitHelper.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class BitHelper
|
||||
{
|
||||
public static bool ReadBit(byte[] byteArray, int bitIndex)
|
||||
{
|
||||
if (bitIndex < 0)
|
||||
throw new ArgumentOutOfRangeException("bitIndex");
|
||||
|
||||
int byteIndex = bitIndex / 8;
|
||||
if (byteIndex >= byteArray.Length)
|
||||
throw new ArgumentOutOfRangeException("bitIndex");
|
||||
|
||||
int bitNumber = bitIndex % 8;
|
||||
byte mask = (byte)(1 << bitNumber);
|
||||
|
||||
return (byteArray[byteIndex] & mask) != 0;
|
||||
}
|
||||
|
||||
public static byte[] WriteBit(byte[] byteArray, int bitIndex, bool value)
|
||||
{
|
||||
if (bitIndex < 0)
|
||||
throw new ArgumentOutOfRangeException("bitIndex");
|
||||
|
||||
int byteIndex = bitIndex / 8;
|
||||
byte[] resultArray;
|
||||
|
||||
if (byteIndex >= byteArray.Length)
|
||||
{
|
||||
// Create a new array with increased size and copy elements from old array
|
||||
resultArray = new byte[byteIndex + 1];
|
||||
Array.Copy(byteArray, resultArray, byteArray.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new array and copy elements from old array
|
||||
resultArray = new byte[byteArray.Length];
|
||||
Array.Copy(byteArray, resultArray, byteArray.Length);
|
||||
}
|
||||
|
||||
int bitNumber = bitIndex % 8;
|
||||
byte mask = (byte)(1 << bitNumber);
|
||||
|
||||
if (value)
|
||||
resultArray[byteIndex] |= mask; // Set the bit to 1
|
||||
else
|
||||
resultArray[byteIndex] &= (byte)~mask; // Set the bit to 0
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
public static byte[] OverwriteByteArrays(byte[] targetArray, byte[] overwriteArray)
|
||||
{
|
||||
int targetLength = targetArray.Length;
|
||||
int overwriteLength = overwriteArray.Length;
|
||||
|
||||
int maxLength = Math.Max(targetLength, overwriteLength);
|
||||
|
||||
byte[] resultArray = new byte[maxLength];
|
||||
|
||||
for (int i = 0; i < maxLength; i++)
|
||||
{
|
||||
byte targetByte = i < targetLength ? targetArray[i] : (byte)0;
|
||||
byte overwriteByte = i < overwriteLength ? overwriteArray[i] : (byte)0;
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
bool overwriteBit = (overwriteByte & (1 << j)) != 0;
|
||||
if (i < targetLength)
|
||||
{
|
||||
bool targetBit = (targetByte & (1 << j)) != 0;
|
||||
if (overwriteBit)
|
||||
{
|
||||
targetByte = targetBit ? (byte)(targetByte | (1 << j)) : (byte)(targetByte & ~(1 << j));
|
||||
}
|
||||
}
|
||||
else if (overwriteBit)
|
||||
{
|
||||
targetByte |= (byte)(1 << j);
|
||||
}
|
||||
}
|
||||
|
||||
resultArray[i] = targetByte;
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
}
|
||||
6
Moonlight/App/Helpers/BlurAttribute.cs
Normal file
6
Moonlight/App/Helpers/BlurAttribute.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class BlurAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
56
Moonlight/App/Helpers/ByteSizeValue.cs
Normal file
56
Moonlight/App/Helpers/ByteSizeValue.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class ByteSizeValue
|
||||
{
|
||||
public long Bytes { get; set; }
|
||||
|
||||
public long KiloBytes
|
||||
{
|
||||
get => Bytes / 1024;
|
||||
set => Bytes = value * 1024;
|
||||
}
|
||||
|
||||
public long MegaBytes
|
||||
{
|
||||
get => KiloBytes / 1024;
|
||||
set => KiloBytes = value * 1024;
|
||||
}
|
||||
|
||||
public long GigaBytes
|
||||
{
|
||||
get => MegaBytes / 1024;
|
||||
set => MegaBytes = value * 1024;
|
||||
}
|
||||
|
||||
public static ByteSizeValue FromBytes(long bytes)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Bytes = bytes
|
||||
};
|
||||
}
|
||||
|
||||
public static ByteSizeValue FromKiloBytes(long kiloBytes)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
KiloBytes = kiloBytes
|
||||
};
|
||||
}
|
||||
|
||||
public static ByteSizeValue FromMegaBytes(long megaBytes)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
MegaBytes = megaBytes
|
||||
};
|
||||
}
|
||||
|
||||
public static ByteSizeValue FromGigaBytes(long gigaBytes)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
GigaBytes = gigaBytes
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
using Logging.Net;
|
||||
using Logging.Net.Loggers.SB;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using ILogger = Logging.Net.ILogger;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class CacheLogger : ILogger
|
||||
{
|
||||
private SBLogger SbLogger = new();
|
||||
private List<LogEntry> Messages = new();
|
||||
|
||||
public LogEntry[] GetMessages()
|
||||
{
|
||||
lock (Messages)
|
||||
{
|
||||
var result = new LogEntry[Messages.Count];
|
||||
Messages.CopyTo(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear(int messages)
|
||||
{
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.RemoveRange(0, Math.Min(messages, Messages.Count));
|
||||
}
|
||||
}
|
||||
|
||||
public void Info(string? s)
|
||||
{
|
||||
if (s == null)
|
||||
return;
|
||||
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "info",
|
||||
Message = s
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.Info(s);
|
||||
}
|
||||
|
||||
public void Debug(string? s)
|
||||
{
|
||||
if (s == null)
|
||||
return;
|
||||
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "debug",
|
||||
Message = s
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.Debug(s);
|
||||
}
|
||||
|
||||
public void Warn(string? s)
|
||||
{
|
||||
if (s == null)
|
||||
return;
|
||||
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "warn",
|
||||
Message = s
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.Warn(s);
|
||||
}
|
||||
|
||||
public void Error(string? s)
|
||||
{
|
||||
if (s == null)
|
||||
return;
|
||||
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "error",
|
||||
Message = s
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.Error(s);
|
||||
}
|
||||
|
||||
public void Fatal(string? s)
|
||||
{
|
||||
if (s == null)
|
||||
return;
|
||||
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "fatal",
|
||||
Message = s
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.Fatal(s);
|
||||
}
|
||||
|
||||
public void InfoEx(Exception ex)
|
||||
{
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "info",
|
||||
Message = ex.ToStringDemystified()
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.InfoEx(ex);
|
||||
}
|
||||
|
||||
public void DebugEx(Exception ex)
|
||||
{
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "debug",
|
||||
Message = ex.ToStringDemystified()
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.DebugEx(ex);
|
||||
}
|
||||
|
||||
public void WarnEx(Exception ex)
|
||||
{
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "warn",
|
||||
Message = ex.ToStringDemystified()
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.WarnEx(ex);
|
||||
}
|
||||
|
||||
public void ErrorEx(Exception ex)
|
||||
{
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "error",
|
||||
Message = ex.ToStringDemystified()
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.ErrorEx(ex);
|
||||
}
|
||||
|
||||
public void FatalEx(Exception ex)
|
||||
{
|
||||
lock (Messages)
|
||||
{
|
||||
Messages.Add(new()
|
||||
{
|
||||
Level = "fatal",
|
||||
Message = ex.ToStringDemystified()
|
||||
});
|
||||
}
|
||||
|
||||
SbLogger.FatalEx(ex);
|
||||
}
|
||||
|
||||
public LoggingConfiguration GetErrorConfiguration()
|
||||
{
|
||||
return SbLogger.GetErrorConfiguration();
|
||||
}
|
||||
|
||||
public void SetErrorConfiguration(LoggingConfiguration configuration)
|
||||
{
|
||||
SbLogger.SetErrorConfiguration(configuration);
|
||||
}
|
||||
|
||||
public LoggingConfiguration GetFatalConfiguration()
|
||||
{
|
||||
return SbLogger.GetFatalConfiguration();
|
||||
}
|
||||
|
||||
public void SetFatalConfiguration(LoggingConfiguration configuration)
|
||||
{
|
||||
SbLogger.SetFatalConfiguration(configuration);
|
||||
}
|
||||
|
||||
public LoggingConfiguration GetWarnConfiguration()
|
||||
{
|
||||
return SbLogger.GetWarnConfiguration();
|
||||
}
|
||||
|
||||
public void SetWarnConfiguration(LoggingConfiguration configuration)
|
||||
{
|
||||
SbLogger.SetWarnConfiguration(configuration);
|
||||
}
|
||||
|
||||
public LoggingConfiguration GetInfoConfiguration()
|
||||
{
|
||||
return SbLogger.GetInfoConfiguration();
|
||||
}
|
||||
|
||||
public void SetInfoConfiguration(LoggingConfiguration configuration)
|
||||
{
|
||||
SbLogger.SetInfoConfiguration(configuration);
|
||||
}
|
||||
|
||||
public LoggingConfiguration GetDebugConfiguration()
|
||||
{
|
||||
return SbLogger.GetDebugConfiguration();
|
||||
}
|
||||
|
||||
public void SetDebugConfiguration(LoggingConfiguration configuration)
|
||||
{
|
||||
SbLogger.SetDebugConfiguration(configuration);
|
||||
}
|
||||
|
||||
public ILoggingAddition GetAddition()
|
||||
{
|
||||
return SbLogger.GetAddition();
|
||||
}
|
||||
|
||||
public void SetAddition(ILoggingAddition addition)
|
||||
{
|
||||
SbLogger.SetAddition(addition);
|
||||
}
|
||||
|
||||
public bool LogCallingClass
|
||||
{
|
||||
get => SbLogger.LogCallingClass;
|
||||
set => SbLogger.LogCallingClass = value;
|
||||
}
|
||||
}
|
||||
12
Moonlight/App/Helpers/ComponentHelper.cs
Normal file
12
Moonlight/App/Helpers/ComponentHelper.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class ComponentHelper
|
||||
{
|
||||
public static RenderFragment FromType(Type type) => builder =>
|
||||
{
|
||||
builder.OpenComponent(0, type);
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using Logging.Net;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moonlight.App.Database;
|
||||
using Moonlight.App.Services;
|
||||
@@ -45,8 +44,19 @@ public class DatabaseCheckupService
|
||||
if (migrations.Any())
|
||||
{
|
||||
Logger.Info($"{migrations.Length} migrations pending. Updating now");
|
||||
|
||||
await BackupDatabase();
|
||||
|
||||
try
|
||||
{
|
||||
var backupHelper = new BackupHelper();
|
||||
await backupHelper.CreateBackup(
|
||||
PathBuilder.File("storage", "backups", $"{new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds()}.zip"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Fatal("Unable to create backup");
|
||||
Logger.Fatal(e);
|
||||
Logger.Fatal("Moonlight will continue to start and apply the migrations without a backup");
|
||||
}
|
||||
|
||||
Logger.Info("Applying migrations");
|
||||
|
||||
@@ -59,42 +69,4 @@ public class DatabaseCheckupService
|
||||
Logger.Info("Database is up-to-date. No migrations have been performed");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task BackupDatabase()
|
||||
{
|
||||
Logger.Info("Creating backup from database");
|
||||
|
||||
var configService = new ConfigService(new StorageService());
|
||||
var dateTimeService = new DateTimeService();
|
||||
|
||||
var config = configService
|
||||
.GetSection("Moonlight")
|
||||
.GetSection("Database");
|
||||
|
||||
var connectionString = $"host={config.GetValue<string>("Host")};" +
|
||||
$"port={config.GetValue<int>("Port")};" +
|
||||
$"database={config.GetValue<string>("Database")};" +
|
||||
$"uid={config.GetValue<string>("Username")};" +
|
||||
$"pwd={config.GetValue<string>("Password")}";
|
||||
|
||||
string file = PathBuilder.File("storage", "backups", $"{dateTimeService.GetCurrentUnix()}-mysql.sql");
|
||||
|
||||
Logger.Info($"Saving it to: {file}");
|
||||
Logger.Info("Starting backup...");
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
await using MySqlConnection conn = new MySqlConnection(connectionString);
|
||||
await using MySqlCommand cmd = new MySqlCommand();
|
||||
using MySqlBackup mb = new MySqlBackup(cmd);
|
||||
|
||||
cmd.Connection = conn;
|
||||
await conn.OpenAsync();
|
||||
mb.ExportToFile(file);
|
||||
await conn.CloseAsync();
|
||||
|
||||
sw.Stop();
|
||||
Logger.Info($"Done. {sw.Elapsed.TotalSeconds}s");
|
||||
}
|
||||
}
|
||||
71
Moonlight/App/Helpers/EggConverter.cs
Normal file
71
Moonlight/App/Helpers/EggConverter.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Text;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public static class EggConverter
|
||||
{
|
||||
public static Image Convert(string json)
|
||||
{
|
||||
var result = new Image();
|
||||
|
||||
var data = new ConfigurationBuilder().AddJsonStream(
|
||||
new MemoryStream(Encoding.ASCII.GetBytes(json))
|
||||
).Build();
|
||||
|
||||
result.Allocations = 1;
|
||||
result.Description = data.GetValue<string>("description") ?? "";
|
||||
result.Uuid = Guid.NewGuid();
|
||||
result.Startup = data.GetValue<string>("startup") ?? "";
|
||||
result.Name = data.GetValue<string>("name") ?? "Ptero Egg";
|
||||
|
||||
foreach (var variable in data.GetSection("variables").GetChildren())
|
||||
{
|
||||
result.Variables.Add(new()
|
||||
{
|
||||
Key = variable.GetValue<string>("env_variable") ?? "",
|
||||
DefaultValue = variable.GetValue<string>("default_value") ?? ""
|
||||
});
|
||||
}
|
||||
|
||||
var configData = data.GetSection("config");
|
||||
|
||||
result.ConfigFiles = configData.GetValue<string>("files") ?? "{}";
|
||||
|
||||
var dImagesData = JObject.Parse(json);
|
||||
var dImages = (JObject)dImagesData["docker_images"]!;
|
||||
|
||||
foreach (var dockerImage in dImages)
|
||||
{
|
||||
var di = new DockerImage()
|
||||
{
|
||||
Default = dockerImage.Key == dImages.Properties().Last().Name,
|
||||
Name = dockerImage.Value!.ToString()
|
||||
};
|
||||
|
||||
result.DockerImages.Add(di);
|
||||
}
|
||||
|
||||
var installSection = data.GetSection("scripts").GetSection("installation");
|
||||
|
||||
result.InstallEntrypoint = installSection.GetValue<string>("entrypoint") ?? "bash";
|
||||
result.InstallScript = installSection.GetValue<string>("script") ?? "";
|
||||
result.InstallDockerImage = installSection.GetValue<string>("container") ?? "";
|
||||
|
||||
var rawJson = configData.GetValue<string>("startup");
|
||||
|
||||
var startupData = new ConfigurationBuilder().AddJsonStream(
|
||||
new MemoryStream(Encoding.ASCII.GetBytes(rawJson!))
|
||||
).Build();
|
||||
|
||||
result.StartupDetection = startupData.GetValue<string>("done", "") ?? "";
|
||||
result.StopCommand = configData.GetValue<string>("stop") ?? "";
|
||||
|
||||
result.TagsJson = "[]";
|
||||
result.BackgroundImageUrl = "";
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Logging.Net;
|
||||
using Renci.SshNet;
|
||||
using Renci.SshNet;
|
||||
using ConnectionInfo = Renci.SshNet.ConnectionInfo;
|
||||
|
||||
namespace Moonlight.App.Helpers.Files;
|
||||
|
||||
@@ -43,19 +43,22 @@ public class WingsFileAccess : FileAccess
|
||||
$"api/servers/{Server.Uuid}/files/list-directory?directory={CurrentPath}"
|
||||
);
|
||||
|
||||
var x = new List<FileData>();
|
||||
var result = new List<FileData>();
|
||||
|
||||
foreach (var response in res)
|
||||
foreach (var resGrouped in res.GroupBy(x => x.Directory))
|
||||
{
|
||||
x.Add(new()
|
||||
foreach (var resItem in resGrouped.OrderBy(x => x.Name))
|
||||
{
|
||||
Name = response.Name,
|
||||
Size = response.File ? response.Size : 0,
|
||||
IsFile = response.File,
|
||||
});
|
||||
result.Add(new()
|
||||
{
|
||||
Name = resItem.Name,
|
||||
Size = resItem.File ? resItem.Size : 0,
|
||||
IsFile = resItem.File,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return x.ToArray();
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public override Task Cd(string dir)
|
||||
@@ -111,7 +114,7 @@ public class WingsFileAccess : FileAccess
|
||||
request.AddParameter("name", "files");
|
||||
request.AddParameter("filename", name);
|
||||
request.AddHeader("Content-Type", "multipart/form-data");
|
||||
request.AddHeader("Origin", ConfigService.GetSection("Moonlight").GetValue<string>("AppUrl"));
|
||||
request.AddHeader("Origin", ConfigService.Get().Moonlight.AppUrl);
|
||||
request.AddFile("files", () =>
|
||||
{
|
||||
return new StreamProgressHelper(dataStream)
|
||||
|
||||
@@ -1,9 +1,37 @@
|
||||
using Moonlight.App.Services;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public static class Formatter
|
||||
{
|
||||
public static string ReplaceEnd(string input, string substringToReplace, string newSubstring)
|
||||
{
|
||||
int lastIndexOfSubstring = input.LastIndexOf(substringToReplace);
|
||||
if (lastIndexOfSubstring >= 0)
|
||||
{
|
||||
input = input.Remove(lastIndexOfSubstring, substringToReplace.Length).Insert(lastIndexOfSubstring, newSubstring);
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
public static string ConvertCamelCaseToSpaces(string input)
|
||||
{
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
foreach (char c in input)
|
||||
{
|
||||
if (char.IsUpper(c))
|
||||
{
|
||||
output.Append(' ');
|
||||
}
|
||||
|
||||
output.Append(c);
|
||||
}
|
||||
|
||||
return output.ToString().Trim();
|
||||
}
|
||||
public static string FormatUptime(double uptime)
|
||||
{
|
||||
TimeSpan t = TimeSpan.FromMilliseconds(uptime);
|
||||
@@ -129,11 +157,47 @@ public static class Formatter
|
||||
}
|
||||
}
|
||||
|
||||
public static double BytesToGb(long bytes)
|
||||
public static double CalculateAverage(List<double> values)
|
||||
{
|
||||
const double gbMultiplier = 1024 * 1024 * 1024; // 1 GB = 1024 MB * 1024 KB * 1024 B
|
||||
if (values == null || values.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("The list cannot be null or empty.");
|
||||
}
|
||||
|
||||
double gigabytes = (double)bytes / gbMultiplier;
|
||||
return gigabytes;
|
||||
double sum = 0;
|
||||
foreach (double value in values)
|
||||
{
|
||||
sum += value;
|
||||
}
|
||||
|
||||
return sum / values.Count;
|
||||
}
|
||||
|
||||
public static double CalculatePercentage(double part, double total)
|
||||
{
|
||||
if (total == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (part / total) * 100;
|
||||
}
|
||||
|
||||
public static RenderFragment FormatLineBreaks(string content)
|
||||
{
|
||||
return builder =>
|
||||
{
|
||||
int i = 0;
|
||||
var arr = content.Split("\n", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
|
||||
foreach (var line in arr)
|
||||
{
|
||||
builder.AddContent(i, line);
|
||||
if (i++ != arr.Length - 1)
|
||||
{
|
||||
builder.AddMarkupContent(i, "<br/>");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Logging.Net;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
|
||||
171
Moonlight/App/Helpers/Logger.cs
Normal file
171
Moonlight/App/Helpers/Logger.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using Moonlight.App.Database;
|
||||
using Moonlight.App.Services;
|
||||
using Moonlight.App.Services.Files;
|
||||
using Serilog;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public static class Logger
|
||||
{
|
||||
// The private static instance of the config service, because we have no di here
|
||||
private static ConfigService ConfigService = new(new StorageService());
|
||||
|
||||
#region String method calls
|
||||
public static void Verbose(string message, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Verbose("{Message}", message);
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(message);
|
||||
}
|
||||
|
||||
public static void Info(string message, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Information("{Message}", message);
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(message);
|
||||
}
|
||||
|
||||
public static void Debug(string message, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Debug("{Message}", message);
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(message);
|
||||
}
|
||||
|
||||
public static void Error(string message, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Error("{Message}", message);
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(message);
|
||||
}
|
||||
|
||||
public static void Warn(string message, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Warning("{Message}", message);
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(message);
|
||||
}
|
||||
|
||||
public static void Fatal(string message, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Fatal("{Message}", message);
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(message);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Exception method calls
|
||||
public static void Verbose(Exception exception, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Verbose(exception, "");
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(exception);
|
||||
}
|
||||
|
||||
public static void Info(Exception exception, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Information(exception, "");
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(exception);
|
||||
}
|
||||
|
||||
public static void Debug(Exception exception, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Debug(exception, "");
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(exception);
|
||||
}
|
||||
|
||||
public static void Error(Exception exception, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Error(exception, "");
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(exception);
|
||||
}
|
||||
|
||||
public static void Warn(Exception exception, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Warning(exception, "");
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(exception);
|
||||
}
|
||||
|
||||
public static void Fatal(Exception exception, string channel = "default")
|
||||
{
|
||||
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||
.Fatal(exception, "");
|
||||
|
||||
if(channel == "security")
|
||||
LogSecurityInDb(exception);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private static string GetNameOfCallingClass(int skipFrames = 4)
|
||||
{
|
||||
string fullName;
|
||||
Type declaringType;
|
||||
|
||||
do
|
||||
{
|
||||
MethodBase method = new StackFrame(skipFrames, false).GetMethod();
|
||||
declaringType = method.DeclaringType;
|
||||
if (declaringType == null)
|
||||
{
|
||||
return method.Name;
|
||||
}
|
||||
skipFrames++;
|
||||
if (declaringType.Name.Contains("<"))
|
||||
fullName = declaringType.ReflectedType.Name;
|
||||
else
|
||||
fullName = declaringType.Name;
|
||||
}
|
||||
while (declaringType.Module.Name.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase) | fullName.Contains("Logger"));
|
||||
|
||||
return fullName;
|
||||
}
|
||||
|
||||
|
||||
private static void LogSecurityInDb(Exception exception)
|
||||
{
|
||||
LogSecurityInDb(exception.ToStringDemystified());
|
||||
}
|
||||
private static void LogSecurityInDb(string text)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
var dataContext = new DataContext(ConfigService);
|
||||
|
||||
dataContext.SecurityLogs.Add(new()
|
||||
{
|
||||
Text = text
|
||||
});
|
||||
|
||||
dataContext.SaveChanges();
|
||||
dataContext.Dispose();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Logging.Net;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Logging.Net;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public static class ParseHelper
|
||||
{
|
||||
|
||||
51
Moonlight/App/Helpers/PropBinder.cs
Normal file
51
Moonlight/App/Helpers/PropBinder.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class PropBinder
|
||||
{
|
||||
private PropertyInfo PropertyInfo;
|
||||
private object DataObject;
|
||||
|
||||
public PropBinder(PropertyInfo propertyInfo, object dataObject)
|
||||
{
|
||||
PropertyInfo = propertyInfo;
|
||||
DataObject = dataObject;
|
||||
}
|
||||
|
||||
public string StringValue
|
||||
{
|
||||
get => (string)PropertyInfo.GetValue(DataObject)!;
|
||||
set => PropertyInfo.SetValue(DataObject, value);
|
||||
}
|
||||
|
||||
public int IntValue
|
||||
{
|
||||
get => (int)PropertyInfo.GetValue(DataObject)!;
|
||||
set => PropertyInfo.SetValue(DataObject, value);
|
||||
}
|
||||
|
||||
public long LongValue
|
||||
{
|
||||
get => (long)PropertyInfo.GetValue(DataObject)!;
|
||||
set => PropertyInfo.SetValue(DataObject, value);
|
||||
}
|
||||
|
||||
public bool BoolValue
|
||||
{
|
||||
get => (bool)PropertyInfo.GetValue(DataObject)!;
|
||||
set => PropertyInfo.SetValue(DataObject, value);
|
||||
}
|
||||
|
||||
public DateTime DateTimeValue
|
||||
{
|
||||
get => (DateTime)PropertyInfo.GetValue(DataObject)!;
|
||||
set => PropertyInfo.SetValue(DataObject, value);
|
||||
}
|
||||
|
||||
public double DoubleValue
|
||||
{
|
||||
get => (double)PropertyInfo.GetValue(DataObject)!;
|
||||
set => PropertyInfo.SetValue(DataObject, value);
|
||||
}
|
||||
}
|
||||
66
Moonlight/App/Helpers/Retry.cs
Normal file
66
Moonlight/App/Helpers/Retry.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class Retry
|
||||
{
|
||||
private List<Type> RetryExceptionTypes;
|
||||
private List<Func<Exception, bool>> RetryFilters;
|
||||
private int RetryTimes = 1;
|
||||
|
||||
public Retry()
|
||||
{
|
||||
RetryExceptionTypes = new();
|
||||
RetryFilters = new();
|
||||
}
|
||||
|
||||
public Retry Times(int times)
|
||||
{
|
||||
RetryTimes = times;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Retry At(Func<Exception, bool> filter)
|
||||
{
|
||||
RetryFilters.Add(filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Retry At<T>()
|
||||
{
|
||||
RetryExceptionTypes.Add(typeof(T));
|
||||
return this;
|
||||
}
|
||||
|
||||
public async Task Call(Func<Task> method)
|
||||
{
|
||||
int triesLeft = RetryTimes;
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
await method.Invoke();
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if(triesLeft < 1) // Throw if no tries left
|
||||
throw;
|
||||
|
||||
if (RetryExceptionTypes.Any(x => x.FullName == e.GetType().FullName))
|
||||
{
|
||||
triesLeft--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RetryFilters.Any(x => x.Invoke(e)))
|
||||
{
|
||||
triesLeft--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Throw if not filtered -> unknown/unhandled
|
||||
throw;
|
||||
}
|
||||
} while (triesLeft >= 0);
|
||||
}
|
||||
}
|
||||
@@ -43,4 +43,15 @@ public static class StringHelper
|
||||
|
||||
return firstChar + restOfString;
|
||||
}
|
||||
|
||||
public static string CutInHalf(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
return input;
|
||||
|
||||
int length = input.Length;
|
||||
int halfLength = length / 2;
|
||||
|
||||
return input.Substring(0, halfLength);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using Logging.Net;
|
||||
using Moonlight.App.Helpers.Wings.Data;
|
||||
using Moonlight.App.Helpers.Wings.Enums;
|
||||
using Moonlight.App.Helpers.Wings.Events;
|
||||
@@ -89,10 +88,6 @@ public class WingsConsole : IDisposable
|
||||
{
|
||||
await Work();
|
||||
}
|
||||
catch (JsonReaderException)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warn("Error connecting to wings console");
|
||||
@@ -223,6 +218,16 @@ public class WingsConsole : IDisposable
|
||||
break;
|
||||
|
||||
case "install output":
|
||||
if (ServerState != ServerState.Installing)
|
||||
{
|
||||
// Because wings is sending "install output" events BEFORE
|
||||
// sending the "install started" event,
|
||||
// we need to set the install state here
|
||||
// See https://github.com/pterodactyl/panel/issues/4853
|
||||
// for more details
|
||||
await UpdateServerState(ServerState.Installing);
|
||||
}
|
||||
|
||||
foreach (var line in eventData.Args)
|
||||
{
|
||||
await SaveMessage(line);
|
||||
@@ -247,6 +252,8 @@ public class WingsConsole : IDisposable
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(JsonReaderException){}
|
||||
catch(JsonSerializationException){}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!Disconnecting)
|
||||
|
||||
@@ -20,7 +20,7 @@ public class WingsConsoleHelper
|
||||
{
|
||||
ServerRepository = serverRepository;
|
||||
|
||||
AppUrl = configService.GetSection("Moonlight").GetValue<string>("AppUrl");
|
||||
AppUrl = configService.Get().Moonlight.AppUrl;
|
||||
}
|
||||
|
||||
public async Task ConnectWings(WingsConsole console, Server server)
|
||||
|
||||
@@ -15,7 +15,7 @@ public class WingsJwtHelper
|
||||
{
|
||||
ConfigService = configService;
|
||||
|
||||
AppUrl = ConfigService.GetSection("Moonlight").GetValue<string>("AppUrl");
|
||||
AppUrl = ConfigService.Get().Moonlight.AppUrl;
|
||||
}
|
||||
|
||||
public string Generate(string secret, Action<Dictionary<string, string>> claimsAction)
|
||||
|
||||
@@ -25,7 +25,7 @@ public class AvatarController : Controller
|
||||
|
||||
try
|
||||
{
|
||||
var url = GravatarController.GetImageUrl(user.Email, 100);
|
||||
var url = GravatarController.GetImageUrl(user.Email.ToLower(), 100);
|
||||
|
||||
using var client = new HttpClient();
|
||||
var res = await client.GetByteArrayAsync(url);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moonlight.App.Services;
|
||||
using Moonlight.App.Services.Sessions;
|
||||
using Stripe;
|
||||
using Stripe.Checkout;
|
||||
|
||||
namespace Moonlight.App.Http.Controllers.Api.Moonlight;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/moonlight/billing")]
|
||||
public class BillingController : Controller
|
||||
{
|
||||
private readonly IdentityService IdentityService;
|
||||
private readonly BillingService BillingService;
|
||||
|
||||
public BillingController(
|
||||
IdentityService identityService,
|
||||
BillingService billingService)
|
||||
{
|
||||
IdentityService = identityService;
|
||||
BillingService = billingService;
|
||||
}
|
||||
|
||||
[HttpGet("cancel")]
|
||||
public async Task<ActionResult> Cancel()
|
||||
{
|
||||
var user = IdentityService.User;
|
||||
|
||||
if (user == null)
|
||||
return Redirect("/login");
|
||||
|
||||
return Redirect("/profile/subscriptions/close");
|
||||
}
|
||||
|
||||
[HttpGet("success")]
|
||||
public async Task<ActionResult> Success()
|
||||
{
|
||||
var user = IdentityService.User;
|
||||
|
||||
if (user == null)
|
||||
return Redirect("/login");
|
||||
|
||||
await BillingService.CompleteCheckout(user);
|
||||
|
||||
return Redirect("/profile/subscriptions/close");
|
||||
}
|
||||
}
|
||||
@@ -30,14 +30,14 @@ public class DiscordBotController : Controller
|
||||
ServerService = serverService;
|
||||
|
||||
var config = configService
|
||||
.GetSection("Moonlight")
|
||||
.GetSection("DiscordBotApi");
|
||||
.Get()
|
||||
.Moonlight.DiscordBotApi;
|
||||
|
||||
Enable = config.GetValue<bool>("Enable");
|
||||
Enable = config.Enable;
|
||||
|
||||
if (Enable)
|
||||
{
|
||||
Token = config.GetValue<string>("Token");
|
||||
Token = config.Token;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,145 +2,166 @@
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Database.Entities.Notification;
|
||||
using Moonlight.App.Models.Notifications;
|
||||
using Moonlight.App.Repositories;
|
||||
using Moonlight.App.Services;
|
||||
using Moonlight.App.Services.Notifications;
|
||||
using Moonlight.App.Services.Sessions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.Http.Controllers.Api.Moonlight.Notifications;
|
||||
|
||||
public class ListenController : ControllerBase
|
||||
[ApiController]
|
||||
[Route("api/moonlight/notification/listen")]
|
||||
public class ListenController : Controller
|
||||
{
|
||||
internal WebSocket ws;
|
||||
private bool active = true;
|
||||
private bool isAuth = false;
|
||||
private WebSocket WebSocket;
|
||||
private NotificationClient Client;
|
||||
|
||||
private readonly IdentityService IdentityService;
|
||||
private readonly NotificationRepository NotificationRepository;
|
||||
private readonly OneTimeJwtService OneTimeJwtService;
|
||||
private readonly NotificationClientService NotificationClientService;
|
||||
private readonly NotificationServerService NotificationServerService;
|
||||
private CancellationTokenSource CancellationTokenSource = new();
|
||||
|
||||
public ListenController(IdentityService identityService,
|
||||
NotificationRepository notificationRepository,
|
||||
OneTimeJwtService oneTimeJwtService,
|
||||
NotificationClientService notificationClientService,
|
||||
NotificationServerService notificationServerService)
|
||||
private User? CurrentUser;
|
||||
|
||||
private readonly OneTimeJwtService OneTimeJwtService;
|
||||
private readonly NotificationServerService NotificationServerService;
|
||||
private readonly Repository<NotificationClient> NotificationClientRepository;
|
||||
|
||||
public ListenController(
|
||||
OneTimeJwtService oneTimeJwtService,
|
||||
NotificationServerService notificationServerService, Repository<NotificationClient> notificationClientRepository)
|
||||
{
|
||||
IdentityService = identityService;
|
||||
NotificationRepository = notificationRepository;
|
||||
OneTimeJwtService = oneTimeJwtService;
|
||||
NotificationClientService = notificationClientService;
|
||||
NotificationServerService = notificationServerService;
|
||||
NotificationClientRepository = notificationClientRepository;
|
||||
}
|
||||
|
||||
|
||||
[Route("/api/moonlight/notifications/listen")]
|
||||
public async Task Get()
|
||||
public async Task<ActionResult> Get()
|
||||
{
|
||||
if (HttpContext.WebSockets.IsWebSocketRequest)
|
||||
{
|
||||
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
||||
ws = webSocket;
|
||||
await Echo();
|
||||
WebSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
||||
|
||||
await ProcessWebsocket();
|
||||
|
||||
return new EmptyResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
return StatusCode(400);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Echo()
|
||||
private async Task ProcessWebsocket()
|
||||
{
|
||||
while (active)
|
||||
while (!CancellationTokenSource.Token.IsCancellationRequested && WebSocket.State == WebSocketState.Open)
|
||||
{
|
||||
byte[] bytes = new byte[1024 * 16];
|
||||
var asg = new ArraySegment<byte>(bytes);
|
||||
var res = await ws.ReceiveAsync(asg, CancellationToken.None);
|
||||
|
||||
var text = Encoding.UTF8.GetString(bytes).Trim('\0');
|
||||
|
||||
var obj = JsonConvert.DeserializeObject<BasicWSModel>(text);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(obj.Action))
|
||||
try
|
||||
{
|
||||
await HandleRequest(text, obj.Action);
|
||||
byte[] buffer = new byte[1024 * 16];
|
||||
_ = await WebSocket.ReceiveAsync(buffer, CancellationTokenSource.Token);
|
||||
var text = Encoding.UTF8.GetString(buffer).Trim('\0');
|
||||
|
||||
var basicWsModel = JsonConvert.DeserializeObject<BasicWSModel>(text) ?? new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(basicWsModel.Action))
|
||||
{
|
||||
await HandleRequest(text, basicWsModel.Action);
|
||||
}
|
||||
|
||||
if (WebSocket.State != WebSocketState.Open)
|
||||
{
|
||||
CancellationTokenSource.Cancel();
|
||||
}
|
||||
}
|
||||
catch (WebSocketException e)
|
||||
{
|
||||
CancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
active = ws.State == WebSocketState.Open;
|
||||
}
|
||||
|
||||
await NotificationServerService.UnRegisterClient(Client);
|
||||
}
|
||||
|
||||
private async Task HandleRequest(string text, string action)
|
||||
{
|
||||
if (!isAuth && action == "login")
|
||||
await Login(text);
|
||||
else if (!isAuth)
|
||||
await ws.SendAsync(Encoding.UTF8.GetBytes("{\"error\": \"Unauthorised\"}"), WebSocketMessageType.Text,
|
||||
WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
|
||||
else switch (action)
|
||||
if (CurrentUser == null && action != "login")
|
||||
{
|
||||
await Send("{\"error\": \"Unauthorised\"}");
|
||||
}
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case "login":
|
||||
await Login(text);
|
||||
break;
|
||||
case "received":
|
||||
await Received(text);
|
||||
break;
|
||||
case "read":
|
||||
await Read(text);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Send(string text)
|
||||
{
|
||||
await WebSocket.SendAsync(
|
||||
Encoding.UTF8.GetBytes(text),
|
||||
WebSocketMessageType.Text,
|
||||
WebSocketMessageFlags.EndOfMessage, CancellationTokenSource.Token
|
||||
);
|
||||
}
|
||||
|
||||
private async Task Login(string json)
|
||||
{
|
||||
var jwt = JsonConvert.DeserializeObject<Login>(json).token;
|
||||
|
||||
var dict = await OneTimeJwtService.Validate(jwt);
|
||||
var loginModel = JsonConvert.DeserializeObject<Login>(json) ?? new();
|
||||
|
||||
var dict = await OneTimeJwtService.Validate(loginModel.Token);
|
||||
|
||||
if (dict == null)
|
||||
{
|
||||
string error = "{\"status\":false}";
|
||||
var bytes = Encoding.UTF8.GetBytes(error);
|
||||
await ws.SendAsync(bytes, WebSocketMessageType.Text, WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
|
||||
await Send("{\"status\":false}");
|
||||
return;
|
||||
}
|
||||
|
||||
var _clientId = dict["clientId"];
|
||||
var clientId = int.Parse(_clientId);
|
||||
if (!int.TryParse(dict["clientId"], out int clientId))
|
||||
{
|
||||
await Send("{\"status\":false}");
|
||||
return;
|
||||
}
|
||||
|
||||
var client = NotificationRepository.GetClients().Include(x => x.User).First(x => x.Id == clientId);
|
||||
Client = NotificationClientRepository
|
||||
.Get()
|
||||
.Include(x => x.User)
|
||||
.First(x => x.Id == clientId);
|
||||
|
||||
Client = client;
|
||||
await InitWebsocket();
|
||||
|
||||
string success = "{\"status\":true}";
|
||||
var byt = Encoding.UTF8.GetBytes(success);
|
||||
await ws.SendAsync(byt, WebSocketMessageType.Text, WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
|
||||
}
|
||||
CurrentUser = Client.User;
|
||||
|
||||
private async Task InitWebsocket()
|
||||
{
|
||||
NotificationClientService.listenController = this;
|
||||
NotificationClientService.WebsocketReady(Client);
|
||||
await NotificationServerService.RegisterClient(WebSocket, Client);
|
||||
|
||||
isAuth = true;
|
||||
await Send("{\"status\":true}");
|
||||
}
|
||||
|
||||
private async Task Received(string json)
|
||||
{
|
||||
var id = JsonConvert.DeserializeObject<NotificationById>(json).notification;
|
||||
|
||||
var id = JsonConvert.DeserializeObject<NotificationById>(json).Notification;
|
||||
|
||||
//TODO: Implement ws notification received
|
||||
}
|
||||
|
||||
private async Task Read(string json)
|
||||
{
|
||||
var id = JsonConvert.DeserializeObject<NotificationById>(json).notification;
|
||||
var model = JsonConvert.DeserializeObject<NotificationById>(json) ?? new();
|
||||
|
||||
await NotificationServerService.SendAction(NotificationClientService.User,
|
||||
JsonConvert.SerializeObject(new NotificationById() {Action = "hide", notification = id}));
|
||||
await NotificationServerService.SendAction(
|
||||
CurrentUser!,
|
||||
JsonConvert.SerializeObject(
|
||||
new NotificationById()
|
||||
{
|
||||
Action = "hide", Notification = model.Notification
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public class RegisterController : Controller
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<TokenRegister>> Register()
|
||||
{
|
||||
var user = await IdentityService.Get();
|
||||
var user = IdentityService.User;
|
||||
|
||||
if (user == null)
|
||||
return NotFound();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Logging.Net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moonlight.App.Helpers;
|
||||
using Moonlight.App.Services;
|
||||
using Moonlight.App.Services.Sessions;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class OAuth2Controller : Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentUser = await IdentityService.Get();
|
||||
var currentUser = IdentityService.User;
|
||||
|
||||
if (currentUser != null)
|
||||
{
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
using System.Text;
|
||||
using Logging.Net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moonlight.App.Helpers;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
using Moonlight.App.Services.Files;
|
||||
using Moonlight.App.Services.LogServices;
|
||||
using Moonlight.App.Services.Sessions;
|
||||
|
||||
namespace Moonlight.App.Http.Controllers.Api.Moonlight;
|
||||
|
||||
@@ -14,13 +8,10 @@ namespace Moonlight.App.Http.Controllers.Api.Moonlight;
|
||||
[Route("api/moonlight/resources")]
|
||||
public class ResourcesController : Controller
|
||||
{
|
||||
private readonly SecurityLogService SecurityLogService;
|
||||
private readonly BucketService BucketService;
|
||||
|
||||
public ResourcesController(SecurityLogService securityLogService,
|
||||
BucketService bucketService)
|
||||
public ResourcesController(BucketService bucketService)
|
||||
{
|
||||
SecurityLogService = securityLogService;
|
||||
BucketService = bucketService;
|
||||
}
|
||||
|
||||
@@ -29,10 +20,7 @@ public class ResourcesController : Controller
|
||||
{
|
||||
if (name.Contains(".."))
|
||||
{
|
||||
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
|
||||
{
|
||||
x.Add<string>(name);
|
||||
});
|
||||
Logger.Warn($"Detected an attempted path transversal. Path: {name}", "security");
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
@@ -52,10 +40,7 @@ public class ResourcesController : Controller
|
||||
{
|
||||
if (name.Contains(".."))
|
||||
{
|
||||
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
|
||||
{
|
||||
x.Add<string>(name);
|
||||
});
|
||||
Logger.Warn($"Detected an attempted path transversal. Path: {name}", "security");
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
@@ -75,10 +60,7 @@ public class ResourcesController : Controller
|
||||
{
|
||||
if (name.Contains(".."))
|
||||
{
|
||||
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
|
||||
{
|
||||
x.Add<string>(name);
|
||||
});
|
||||
Logger.Warn($"Detected an attempted path transversal. Path: {name}", "security");
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
using Logging.Net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Events;
|
||||
using Moonlight.App.Http.Requests.Daemon;
|
||||
using Moonlight.App.Repositories;
|
||||
using Moonlight.App.Services;
|
||||
using Moonlight.App.Services.Background;
|
||||
|
||||
namespace Moonlight.App.Http.Controllers.Api.Remote;
|
||||
|
||||
@@ -12,19 +11,17 @@ namespace Moonlight.App.Http.Controllers.Api.Remote;
|
||||
[Route("api/remote/ddos")]
|
||||
public class DdosController : Controller
|
||||
{
|
||||
private readonly NodeRepository NodeRepository;
|
||||
private readonly EventSystem Event;
|
||||
private readonly DdosAttackRepository DdosAttackRepository;
|
||||
private readonly Repository<Node> NodeRepository;
|
||||
private readonly DdosProtectionService DdosProtectionService;
|
||||
|
||||
public DdosController(NodeRepository nodeRepository, EventSystem eventSystem, DdosAttackRepository ddosAttackRepository)
|
||||
public DdosController(Repository<Node> nodeRepository, DdosProtectionService ddosProtectionService)
|
||||
{
|
||||
NodeRepository = nodeRepository;
|
||||
Event = eventSystem;
|
||||
DdosAttackRepository = ddosAttackRepository;
|
||||
DdosProtectionService = ddosProtectionService;
|
||||
}
|
||||
|
||||
[HttpPost("update")]
|
||||
public async Task<ActionResult> Update([FromBody] DdosStatus ddosStatus)
|
||||
[HttpPost("start")]
|
||||
public async Task<ActionResult> Start([FromBody] DdosStart ddosStart)
|
||||
{
|
||||
var tokenData = Request.Headers.Authorization.ToString().Replace("Bearer ", "");
|
||||
var id = tokenData.Split(".")[0];
|
||||
@@ -37,18 +34,26 @@ public class DdosController : Controller
|
||||
|
||||
if (token != node.Token)
|
||||
return Unauthorized();
|
||||
|
||||
await DdosProtectionService.ProcessDdosSignal(ddosStart.Ip, ddosStart.Packets);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
var ddosAttack = new DdosAttack()
|
||||
{
|
||||
Ongoing = ddosStatus.Ongoing,
|
||||
Data = ddosStatus.Data,
|
||||
Ip = ddosStatus.Ip,
|
||||
Node = node
|
||||
};
|
||||
[HttpPost("stop")]
|
||||
public async Task<ActionResult> Stop([FromBody] DdosStop ddosStop)
|
||||
{
|
||||
var tokenData = Request.Headers.Authorization.ToString().Replace("Bearer ", "");
|
||||
var id = tokenData.Split(".")[0];
|
||||
var token = tokenData.Split(".")[1];
|
||||
|
||||
ddosAttack = DdosAttackRepository.Add(ddosAttack);
|
||||
var node = NodeRepository.Get().FirstOrDefault(x => x.TokenId == id);
|
||||
|
||||
await Event.Emit("node.ddos", ddosAttack);
|
||||
if (node == null)
|
||||
return NotFound();
|
||||
|
||||
if (token != node.Token)
|
||||
return Unauthorized();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
7
Moonlight/App/Http/Requests/Daemon/DdosStart.cs
Normal file
7
Moonlight/App/Http/Requests/Daemon/DdosStart.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Moonlight.App.Http.Requests.Daemon;
|
||||
|
||||
public class DdosStart
|
||||
{
|
||||
public string Ip { get; set; } = "";
|
||||
public long Packets { get; set; }
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Moonlight.App.Http.Requests.Daemon;
|
||||
|
||||
public class DdosStatus
|
||||
{
|
||||
public bool Ongoing { get; set; }
|
||||
public long Data { get; set; }
|
||||
public string Ip { get; set; } = "";
|
||||
}
|
||||
7
Moonlight/App/Http/Requests/Daemon/DdosStop.cs
Normal file
7
Moonlight/App/Http/Requests/Daemon/DdosStop.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Moonlight.App.Http.Requests.Daemon;
|
||||
|
||||
public class DdosStop
|
||||
{
|
||||
public string Ip { get; set; } = "";
|
||||
public long Traffic { get; set; }
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Logging.Net;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
using Moonlight.App.Helpers;
|
||||
|
||||
namespace Moonlight.App.LogMigrator;
|
||||
|
||||
@@ -28,19 +27,39 @@ public class LogMigrator : ILogger
|
||||
switch (logLevel)
|
||||
{
|
||||
case LogLevel.Critical:
|
||||
Logger.Fatal($"[{Name}] {formatter(state, exception)}");
|
||||
Logger.Fatal(formatter(state, exception));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Fatal(exception);
|
||||
|
||||
break;
|
||||
case LogLevel.Warning:
|
||||
Logger.Warn($"[{Name}] {formatter(state, exception)}");
|
||||
Logger.Warn(formatter(state, exception));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Warn(exception);
|
||||
|
||||
break;
|
||||
case LogLevel.Debug:
|
||||
Logger.Debug($"[{Name}] {formatter(state, exception)}");
|
||||
Logger.Debug(formatter(state, exception));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Debug(exception);
|
||||
|
||||
break;
|
||||
case LogLevel.Error:
|
||||
Logger.Error($"[{Name}] {formatter(state, exception)}");
|
||||
Logger.Error(formatter(state, exception));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Error(exception);
|
||||
|
||||
break;
|
||||
case LogLevel.Information:
|
||||
Logger.Info($"[{Name}] {formatter(state, exception)}");
|
||||
Logger.Info(formatter(state, exception));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Info(exception);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
71
Moonlight/App/LogMigrator/SentryDiagnosticsLogger.cs
Normal file
71
Moonlight/App/LogMigrator/SentryDiagnosticsLogger.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using Moonlight.App.Helpers;
|
||||
using Sentry;
|
||||
using Sentry.Extensibility;
|
||||
|
||||
namespace Moonlight.App.LogMigrator;
|
||||
|
||||
public class SentryDiagnosticsLogger : IDiagnosticLogger
|
||||
{
|
||||
private readonly SentryLevel Level;
|
||||
|
||||
public SentryDiagnosticsLogger(SentryLevel level)
|
||||
{
|
||||
Level = level;
|
||||
}
|
||||
|
||||
public bool IsEnabled(SentryLevel level)
|
||||
{
|
||||
if ((int)level >= (int)Level)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Log(SentryLevel logLevel, string message, Exception? exception = null, params object?[] args)
|
||||
{
|
||||
switch (logLevel)
|
||||
{
|
||||
case SentryLevel.Debug:
|
||||
Logger.Debug(string.Format(message, args));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Debug(exception);
|
||||
|
||||
break;
|
||||
|
||||
case SentryLevel.Info:
|
||||
Logger.Info(string.Format(message, args));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Info(exception);
|
||||
|
||||
break;
|
||||
|
||||
case SentryLevel.Warning:
|
||||
Logger.Warn(string.Format(message, args));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Warn(exception);
|
||||
|
||||
break;
|
||||
|
||||
case SentryLevel.Error:
|
||||
Logger.Error(string.Format(message, args));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Error(exception);
|
||||
|
||||
break;
|
||||
|
||||
case SentryLevel.Fatal:
|
||||
Logger.Fatal(string.Format(message, args));
|
||||
|
||||
if(exception != null)
|
||||
Logger.Fatal(exception);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Moonlight/App/MalwareScans/DiscordNukeScan.cs
Normal file
54
Moonlight/App/MalwareScans/DiscordNukeScan.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.MalwareScans;
|
||||
|
||||
public class DiscordNukeScan : MalwareScan
|
||||
{
|
||||
public override string Name => "Discord nuke";
|
||||
public override string Description => "Discord nuke bot detector";
|
||||
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
|
||||
{
|
||||
var serverService = serviceProvider.GetRequiredService<ServerService>();
|
||||
var access = await serverService.CreateFileAccess(server, null!);
|
||||
|
||||
var files = await access.Ls();
|
||||
var filteredFiles = files.Where(x =>
|
||||
x.Name.EndsWith(".py") ||
|
||||
x.Name.EndsWith(".js") ||
|
||||
x.Name.EndsWith(".json") ||
|
||||
x.Name.EndsWith(".env"));
|
||||
|
||||
foreach (var file in filteredFiles)
|
||||
{
|
||||
var content = await access.Read(file);
|
||||
var filteredContent = content.ToLower();
|
||||
|
||||
if (filteredContent.Contains("quake") ||
|
||||
filteredContent.Contains("nuked by") ||
|
||||
filteredContent.Contains("nuke bot") ||
|
||||
(filteredContent.Contains("fucked by") && filteredContent.Contains("nuke"))) // fucked by in context with nuke
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Title = "Discord nuke bot",
|
||||
Description = "Found suspicious content which may indicate there is a nuke bot running",
|
||||
Author = "Marcel Baumgartner"
|
||||
};
|
||||
}
|
||||
|
||||
if (files.Any(x => x.Name == "nukes.json"))
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Title = "Discord nuke bot",
|
||||
Description = "Found suspicious content which may indicate there is a nuke bot running",
|
||||
Author = "Marcel Baumgartner"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
39
Moonlight/App/MalwareScans/FakePlayerPluginScan.cs
Normal file
39
Moonlight/App/MalwareScans/FakePlayerPluginScan.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.MalwareScans;
|
||||
|
||||
public class FakePlayerPluginScan : MalwareScan
|
||||
{
|
||||
public override string Name => "Fake player plugin scan";
|
||||
public override string Description => "This scan is a simple fake player plugin scan provided by moonlight";
|
||||
|
||||
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
|
||||
{
|
||||
var serverService = serviceProvider.GetRequiredService<ServerService>();
|
||||
var access = await serverService.CreateFileAccess(server, null!);
|
||||
var fileElements = await access.Ls();
|
||||
|
||||
if (fileElements.Any(x => !x.IsFile && x.Name == "plugins")) // Check for plugins folder
|
||||
{
|
||||
await access.Cd("plugins");
|
||||
fileElements = await access.Ls();
|
||||
|
||||
foreach (var fileElement in fileElements)
|
||||
{
|
||||
if (fileElement.Name.ToLower().Contains("fakeplayer"))
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Title = "Fake player plugin",
|
||||
Description = $"Suspicious plugin file: {fileElement.Name}",
|
||||
Author = "Marcel Baumgartner"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
37
Moonlight/App/MalwareScans/MinerJarScan.cs
Normal file
37
Moonlight/App/MalwareScans/MinerJarScan.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.MalwareScans;
|
||||
|
||||
public class MinerJarScan : MalwareScan
|
||||
{
|
||||
public override string Name => "Miner jar scan";
|
||||
public override string Description => "This scan is a simple miner jar scan provided by moonlight";
|
||||
|
||||
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
|
||||
{
|
||||
var serverService = serviceProvider.GetRequiredService<ServerService>();
|
||||
var access = await serverService.CreateFileAccess(server, null!);
|
||||
var fileElements = await access.Ls();
|
||||
|
||||
if (fileElements.Any(x => x.Name == "libraries" && !x.IsFile))
|
||||
{
|
||||
await access.Cd("libraries");
|
||||
|
||||
fileElements = await access.Ls();
|
||||
|
||||
if (fileElements.Any(x => x.Name == "jdk" && !x.IsFile))
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Title = "Found Miner",
|
||||
Description = "Detected suspicious library directory which may contain a script for miners",
|
||||
Author = "Marcel Baumgartner"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
35
Moonlight/App/MalwareScans/MinerScan.cs
Normal file
35
Moonlight/App/MalwareScans/MinerScan.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.MalwareScans;
|
||||
|
||||
public class MinerScan : MalwareScan
|
||||
{
|
||||
public override string Name => "Miner (NEZHA)";
|
||||
public override string Description => "Probably a miner";
|
||||
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
|
||||
{
|
||||
var serverService = serviceProvider.GetRequiredService<ServerService>();
|
||||
|
||||
var access = await serverService.CreateFileAccess(server, null!);
|
||||
var files = await access.Ls();
|
||||
|
||||
foreach (var file in files.Where(x => x.IsFile && (x.Name.EndsWith(".sh") || x.Name.EndsWith(".yml")) || x.Name == "bed"))
|
||||
{
|
||||
var content = await access.Read(file);
|
||||
|
||||
if (content.ToLower().Contains("nezha"))
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Title = "Miner",
|
||||
Description = "Miner start script (NEZHA)",
|
||||
Author = "Marcel Baumgartner"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
36
Moonlight/App/MalwareScans/ProxyScan.cs
Normal file
36
Moonlight/App/MalwareScans/ProxyScan.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.MalwareScans;
|
||||
|
||||
public class ProxyScan : MalwareScan
|
||||
{
|
||||
public override string Name => "Proxy software";
|
||||
public override string Description => "Software to use nodes as a proxy";
|
||||
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
|
||||
{
|
||||
var serverService = serviceProvider.GetRequiredService<ServerService>();
|
||||
var access = await serverService.CreateFileAccess(server, null!);
|
||||
|
||||
var files = await access.Ls();
|
||||
|
||||
foreach (var file in files.Where(x => x.Name.EndsWith(".sh")))
|
||||
{
|
||||
var fileContent = await access.Read(file);
|
||||
var processableContent = fileContent.ToLower();
|
||||
|
||||
if (processableContent.Contains("t-e-s-tweb"))
|
||||
{
|
||||
return new MalwareScanResult()
|
||||
{
|
||||
Title = "Proxy software",
|
||||
Description = "Software to use nodes as a proxy",
|
||||
Author = "Marcel Baumgartner"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
35
Moonlight/App/MalwareScans/SelfBotCodeScan.cs
Normal file
35
Moonlight/App/MalwareScans/SelfBotCodeScan.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.MalwareScans;
|
||||
|
||||
public class SelfBotCodeScan : MalwareScan
|
||||
{
|
||||
public override string Name => "Selfbot code scan";
|
||||
public override string Description => "This scan is a simple selfbot code scan provided by moonlight";
|
||||
|
||||
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
|
||||
{
|
||||
var serverService = serviceProvider.GetRequiredService<ServerService>();
|
||||
var access = await serverService.CreateFileAccess(server, null!);
|
||||
var fileElements = await access.Ls();
|
||||
|
||||
foreach (var script in fileElements.Where(x => x.Name.EndsWith(".py") && x.IsFile))
|
||||
{
|
||||
var rawScript = await access.Read(script);
|
||||
|
||||
if (rawScript.Contains("https://discord.com/api") && !rawScript.Contains("https://discord.com/api/oauth2") && !rawScript.Contains("https://discord.com/api/webhook") || rawScript.Contains("https://rblxwild.com")) //TODO: Export to plugins, add regex for checking
|
||||
{
|
||||
return new MalwareScanResult
|
||||
{
|
||||
Title = "Potential selfbot",
|
||||
Description = $"Suspicious script file: {script.Name}",
|
||||
Author = "Marcel Baumgartner"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
30
Moonlight/App/MalwareScans/SelfBotScan.cs
Normal file
30
Moonlight/App/MalwareScans/SelfBotScan.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.MalwareScans;
|
||||
|
||||
public class SelfBotScan : MalwareScan
|
||||
{
|
||||
public override string Name => "Selfbot Scan";
|
||||
public override string Description => "This scan is a simple selfbot scan provided by moonlight";
|
||||
|
||||
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
|
||||
{
|
||||
var serverService = serviceProvider.GetRequiredService<ServerService>();
|
||||
var access = await serverService.CreateFileAccess(server, null!);
|
||||
var fileElements = await access.Ls();
|
||||
|
||||
if (fileElements.Any(x => x.Name == "tokens.txt"))
|
||||
{
|
||||
return new MalwareScanResult
|
||||
{
|
||||
Title = "Found SelfBot",
|
||||
Description = "Detected suspicious 'tokens.txt' file which may contain tokens for a selfbot",
|
||||
Author = "Marcel Baumgartner"
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
21
Moonlight/App/Models/Forms/CreateTicketDataModel.cs
Normal file
21
Moonlight/App/Models/Forms/CreateTicketDataModel.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Moonlight.App.Models.Misc;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class CreateTicketDataModel
|
||||
{
|
||||
[Required(ErrorMessage = "You need to specify a issue topic")]
|
||||
[MinLength(5, ErrorMessage = "The issue topic needs to be longer than 5 characters")]
|
||||
public string IssueTopic { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "You need to specify a issue description")]
|
||||
[MinLength(10, ErrorMessage = "The issue description needs to be longer than 10 characters")]
|
||||
public string IssueDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "You need to specify your tries to solve this issue")]
|
||||
public string IssueTries { get; set; }
|
||||
|
||||
public TicketSubject Subject { get; set; }
|
||||
public int SubjectId { get; set; }
|
||||
}
|
||||
8
Moonlight/App/Models/Forms/ServerImageDataModel.cs
Normal file
8
Moonlight/App/Models/Forms/ServerImageDataModel.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class ServerImageDataModel
|
||||
{
|
||||
public string OverrideStartup { get; set; }
|
||||
|
||||
public int DockerImageIndex { get; set; }
|
||||
}
|
||||
14
Moonlight/App/Models/Forms/ServerOverviewDataModel.cs
Normal file
14
Moonlight/App/Models/Forms/ServerOverviewDataModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Moonlight.App.Database.Entities;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class ServerOverviewDataModel
|
||||
{
|
||||
[Required(ErrorMessage = "You need to enter a name")]
|
||||
[MaxLength(32, ErrorMessage = "The name cannot be longer that 32 characters")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "You need to specify a owner")]
|
||||
public User Owner { get; set; }
|
||||
}
|
||||
15
Moonlight/App/Models/Forms/ServerResourcesDataModel.cs
Normal file
15
Moonlight/App/Models/Forms/ServerResourcesDataModel.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class ServerResourcesDataModel
|
||||
{
|
||||
[Required(ErrorMessage = "You need to specify the cpu cores")]
|
||||
public int Cpu { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "You need to specify the memory")]
|
||||
public long Memory { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "You need to specify the disk")]
|
||||
public long Disk { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Moonlight.App.Models.Misc;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
@@ -10,4 +11,8 @@ public class SubscriptionDataModel
|
||||
|
||||
[Required(ErrorMessage = "You need to enter a description")]
|
||||
public string Description { get; set; } = "";
|
||||
|
||||
public double Price { get; set; } = 0;
|
||||
public Currency Currency { get; set; } = Currency.USD;
|
||||
public int Duration { get; set; } = 30;
|
||||
}
|
||||
34
Moonlight/App/Models/Forms/UserEditDataModel.cs
Normal file
34
Moonlight/App/Models/Forms/UserEditDataModel.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class UserEditDataModel
|
||||
{
|
||||
[Required]
|
||||
public string FirstName { get; set; } = "";
|
||||
|
||||
[Required]
|
||||
public string LastName { get; set; } = "";
|
||||
|
||||
[Required]
|
||||
public string Email { get; set; } = "";
|
||||
|
||||
[Required]
|
||||
public string Address { get; set; } = "";
|
||||
|
||||
[Required]
|
||||
public string City { get; set; } = "";
|
||||
|
||||
[Required]
|
||||
public string State { get; set; } = "";
|
||||
|
||||
[Required]
|
||||
public string Country { get; set; } = "";
|
||||
|
||||
public bool Admin { get; set; }
|
||||
public bool TotpEnabled { get; set; }
|
||||
public ulong DiscordId { get; set; }
|
||||
public PermissionGroup? PermissionGroup { get; set; }
|
||||
}
|
||||
6
Moonlight/App/Models/Forms/UserPreferencesDataModel.cs
Normal file
6
Moonlight/App/Models/Forms/UserPreferencesDataModel.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class UserPreferencesDataModel
|
||||
{
|
||||
public bool StreamerMode { get; set; } = false;
|
||||
}
|
||||
19
Moonlight/App/Models/Misc/ActiveNotificationClient.cs
Normal file
19
Moonlight/App/Models/Misc/ActiveNotificationClient.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using Moonlight.App.Database.Entities.Notification;
|
||||
|
||||
namespace Moonlight.App.Models.Misc;
|
||||
|
||||
public class ActiveNotificationClient
|
||||
{
|
||||
public WebSocket WebSocket { get; set; }
|
||||
public NotificationClient Client { get; set; }
|
||||
|
||||
public async Task SendAction(string action)
|
||||
{
|
||||
await WebSocket.SendAsync(
|
||||
Encoding.UTF8.GetBytes(action),
|
||||
WebSocketMessageType.Text,
|
||||
WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
namespace Moonlight.App.Models.Misc;
|
||||
|
||||
public enum AuditLogType
|
||||
{
|
||||
Login,
|
||||
Register,
|
||||
ChangePassword,
|
||||
ChangePowerState,
|
||||
CreateBackup,
|
||||
RestoreBackup,
|
||||
DeleteBackup,
|
||||
DownloadBackup,
|
||||
CreateServer,
|
||||
ReinstallServer,
|
||||
CancelSubscription,
|
||||
ApplySubscriptionCode,
|
||||
EnableTotp,
|
||||
DisableTotp,
|
||||
AddDomainRecord,
|
||||
UpdateDomainRecord,
|
||||
DeleteDomainRecord,
|
||||
PasswordReset,
|
||||
CleanupEnabled,
|
||||
CleanupDisabled,
|
||||
CleanupTriggered,
|
||||
PasswordChange,
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user