mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-05-10 12:12:27 +00:00
Implement YML configuration
- Sorts config better - Stored in a robust format - Migrates from old JSON format automatically on startup - Retains version migration feature - Renames ServerSettings to ServerConfiguration
This commit is contained in:
parent
9d80f1e178
commit
9d74a4104b
53 changed files with 630 additions and 302 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -23,6 +23,7 @@ png/
|
|||
/ProjectLighthouse/r/*
|
||||
/ProjectLighthouse/logs/*
|
||||
lighthouse.config.json
|
||||
lighthouse.yml
|
||||
gitBranch.txt
|
||||
gitVersion.txt
|
||||
gitRemotes.txt
|
||||
|
|
5
.idea/.idea.ProjectLighthouse/.idea/misc.xml
generated
5
.idea/.idea.ProjectLighthouse/.idea/misc.xml
generated
|
@ -1,10 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SwUserDefinedSpecifications">
|
||||
<option name="specTypeByUrl">
|
||||
<map />
|
||||
</option>
|
||||
</component>
|
||||
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
|
||||
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
|
||||
</component>
|
||||
|
|
|
@ -10,8 +10,8 @@ public sealed class DatabaseFactAttribute : FactAttribute
|
|||
|
||||
public DatabaseFactAttribute()
|
||||
{
|
||||
ServerSettings.Instance = new ServerSettings();
|
||||
ServerSettings.Instance.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse";
|
||||
ServerConfiguration.Instance = new ServerConfiguration();
|
||||
ServerConfiguration.Instance.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse";
|
||||
if (!ServerStatics.DbConnected) this.Skip = "Database not available";
|
||||
else
|
||||
lock(migrateLock)
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BE/@EntryIndexedValue">BE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DB/@EntryIndexedValue">DB</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DDS/@EntryIndexedValue">DDS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DLC/@EntryIndexedValue">DLC</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
|
||||
|
@ -89,6 +90,7 @@
|
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PSP/@EntryIndexedValue">PSP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RPCS/@EntryIndexedValue">RPCS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SMTP/@EntryIndexedValue">SMTP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SSL/@EntryIndexedValue">SSL</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TLS/@EntryIndexedValue">TLS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Method/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
|
|
|
@ -33,7 +33,7 @@ public class ClientConfigurationController : ControllerBase
|
|||
"ProbabilityOfPacketDelay 0.0\nMinPacketDelayFrames 0\nMaxPacketDelayFrames 3\nProbabilityOfPacketDrop 0.0\nEnableFakeConditionsForLoopback true\nNumberOfFramesPredictionAllowedForNonLocalPlayer 1000\nEnablePrediction true\nMinPredictedFrames 0\nMaxPredictedFrames 10\nAllowGameRendCameraSplit true\nFramesBeforeAgressiveCatchup 30\nPredictionPadSides 200\nPredictionPadTop 200\nPredictionPadBottom 200\nShowErrorNumbers true\nAllowModeratedLevels false\nAllowModeratedPoppetItems false\nTIMEOUT_WAIT_FOR_JOIN_RESPONSE_FROM_PREV_PARTY_HOST 50.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_HOST 30.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_MEMBER 45.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN_FRIEND 15.0\nTIMEOUT_WAIT_FOR_CONNECTION_FROM_HOST 30.0\nTIMEOUT_WAIT_FOR_ROOM_ID_TO_JOIN 60.0\nTIMEOUT_WAIT_FOR_GET_NUM_PLAYERS_ONLINE 60.0\nTIMEOUT_WAIT_FOR_SIGNALLING_CONNECTIONS 120.0\nTIMEOUT_WAIT_FOR_PARTY_DATA 60.0\nTIME_TO_WAIT_FOR_LEAVE_MESSAGE_TO_COME_BACK 20.0\nTIME_TO_WAIT_FOR_FOLLOWING_REQUESTS_TO_ARRIVE 30.0\nTIMEOUT_WAIT_FOR_FINISHED_MIGRATING_HOST 30.0\nTIMEOUT_WAIT_FOR_PARTY_LEADER_FINISH_JOINING 45.0\nTIMEOUT_WAIT_FOR_QUICKPLAY_LEVEL 60.0\nTIMEOUT_WAIT_FOR_PLAYERS_TO_JOIN 30.0\nTIMEOUT_WAIT_FOR_DIVE_IN_PLAYERS 240.0\nTIMEOUT_WAIT_FOR_FIND_BEST_ROOM 60.0\nTIMEOUT_DIVE_IN_TOTAL 300.0\nTIMEOUT_WAIT_FOR_SOCKET_CONNECTION 120.0\nTIMEOUT_WAIT_FOR_REQUEST_RESOURCE_MESSAGE 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_GET_RESOURCE_LIST 120.0\nTIMEOUT_WAIT_FOR_CLIENT_TO_LOAD_RESOURCES 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_SAVE_GAME_STATE 30.0\nTIMEOUT_WAIT_FOR_ADD_PLAYERS_TO_TAKE 30.0\nTIMEOUT_WAIT_FOR_UPDATE_FROM_CLIENT 90.0\nTIMEOUT_WAIT_FOR_HOST_TO_GET_RESOURCE_LIST 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_SAVE_GAME_STATE 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_ADD_US 30.0\nTIMEOUT_WAIT_FOR_UPDATE 60.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN 50.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_PRESENCE 60.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_CONNECTION 120.0\nSECONDS_BETWEEN_PINS_AWARDED_UPLOADS 300.0\nEnableKeepAlive true\nAllowVoIPRecordingPlayback true\nOverheatingThresholdDisallowMidgameJoin 0.95\nMaxCatchupFrames 3\nMaxLagBeforeShowLoading 23\nMinLagBeforeHideLoading 30\nLagImprovementInflectionPoint -1.0\nFlickerThreshold 2.0\nClosedDemo2014Version 1\nClosedDemo2014Expired false\nEnablePlayedFilter true\nEnableCommunityDecorations true\nGameStateUpdateRate 10.0\nGameStateUpdateRateWithConsumers 1.0\nDisableDLCPublishCheck false\nEnableDiveIn true\nEnableHackChecks false\nAllowOnlineCreate true" +
|
||||
$"TelemetryServer {hostname}\n" +
|
||||
$"CDNHostName {hostname}\n" +
|
||||
$"ShowLevelBoos {ServerSettings.Instance.BooingEnabled.ToString().ToLower()}\n"
|
||||
$"ShowLevelBoos {ServerConfiguration.Instance.UserGeneratedContentLimits.BooingEnabled.ToString().ToLower()}\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,9 +81,9 @@ public class LoginController : ControllerBase
|
|||
return this.StatusCode(403, "");
|
||||
}
|
||||
|
||||
if (ServerSettings.Instance.UseExternalAuth)
|
||||
if (ServerConfiguration.Instance.Authentication.UseExternalAuth)
|
||||
{
|
||||
if (ServerSettings.Instance.BlockDeniedUsers)
|
||||
if (ServerConfiguration.Instance.Authentication.BlockDeniedUsers)
|
||||
{
|
||||
string ipAddressAndName = $"{token.UserLocation}|{user.Username}";
|
||||
if (DeniedAuthenticationHelper.RecentlyDenied(ipAddressAndName) || DeniedAuthenticationHelper.GetAttempts(ipAddressAndName) > 3)
|
||||
|
|
|
@ -41,7 +41,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
|
|||
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
return this.Ok($"{license}\n{ServerSettings.Instance.EulaText}");
|
||||
return this.Ok($"{license}\n{ServerConfiguration.Instance.EulaText}");
|
||||
}
|
||||
|
||||
[HttpGet("announce")]
|
||||
|
@ -60,7 +60,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
|
|||
GameToken gameToken = userAndToken.Value.Item2;
|
||||
#endif
|
||||
|
||||
string announceText = ServerSettings.Instance.AnnounceText;
|
||||
string announceText = ServerConfiguration.Instance.AnnounceText;
|
||||
|
||||
announceText = announceText.Replace("%user", user.Username);
|
||||
announceText = announceText.Replace("%id", user.UserId.ToString());
|
||||
|
|
|
@ -34,7 +34,7 @@ public class PhotosController : ControllerBase
|
|||
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
if (user.PhotosByMe >= ServerSettings.Instance.PhotosQuota) return this.BadRequest();
|
||||
if (user.PhotosByMe >= ServerConfiguration.Instance.UserGeneratedContentLimits.PhotosQuota) return this.BadRequest();
|
||||
|
||||
this.Request.Body.Position = 0;
|
||||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
@ -99,7 +99,7 @@ public class PhotosController : ControllerBase
|
|||
{
|
||||
Title = "New photo uploaded!",
|
||||
Description = $"{user.Username} uploaded a new photo.",
|
||||
ImageUrl = $"{ServerSettings.Instance.ExternalUrl}/gameAssets/{photo.LargeHash}",
|
||||
ImageUrl = $"{ServerConfiguration.Instance.ExternalUrl}/gameAssets/{photo.LargeHash}",
|
||||
Color = WebhookHelper.UnionColor,
|
||||
}
|
||||
);
|
||||
|
|
|
@ -56,7 +56,7 @@ public class PublishController : ControllerBase
|
|||
if (oldSlot == null) return this.NotFound();
|
||||
if (oldSlot.CreatorId != user.UserId) return this.BadRequest();
|
||||
}
|
||||
else if (user.GetUsedSlotsForGame(gameToken.GameVersion) > ServerSettings.Instance.EntitledSlots)
|
||||
else if (user.GetUsedSlotsForGame(gameToken.GameVersion) > ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
|
||||
{
|
||||
return this.StatusCode(403, "");
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ public class PublishController : ControllerBase
|
|||
return this.Ok(oldSlot.Serialize(gameToken.GameVersion));
|
||||
}
|
||||
|
||||
if (user.GetUsedSlotsForGame(gameToken.GameVersion) > ServerSettings.Instance.EntitledSlots)
|
||||
if (user.GetUsedSlotsForGame(gameToken.GameVersion) > ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
|
||||
{
|
||||
return this.StatusCode(403, "");
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ public class PublishController : ControllerBase
|
|||
await WebhookHelper.SendWebhook
|
||||
(
|
||||
"New level published!",
|
||||
$"**{user.Username}** just published a new level: [**{slot.Name}**]({ServerSettings.Instance.ExternalUrl}/slot/{slot.SlotId})\n{slot.Description}"
|
||||
$"**{user.Username}** just published a new level: [**{slot.Name}**]({ServerConfiguration.Instance.ExternalUrl}/slot/{slot.SlotId})\n{slot.Description}"
|
||||
);
|
||||
|
||||
return this.Ok(slot.Serialize(gameToken.GameVersion));
|
||||
|
@ -232,7 +232,7 @@ public class PublishController : ControllerBase
|
|||
|
||||
XmlSerializer serializer = new(typeof(Slot));
|
||||
Slot? slot = (Slot?)serializer.Deserialize(new StringReader(bodyString));
|
||||
|
||||
|
||||
SanitizationHelper.SanitizeStringsInClass(slot);
|
||||
|
||||
return slot;
|
||||
|
|
|
@ -42,7 +42,7 @@ public class SlotsController : ControllerBase
|
|||
this.database.Slots.ByGameVersion(gameVersion, token.UserId == user.UserId, true)
|
||||
.Where(s => s.Creator!.Username == user.Username)
|
||||
.Skip(pageStart - 1)
|
||||
.Take(Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)),
|
||||
.Take(Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)),
|
||||
string.Empty,
|
||||
(current, slot) => current + slot.Serialize(token.GameVersion)
|
||||
);
|
||||
|
@ -56,7 +56,7 @@ public class SlotsController : ControllerBase
|
|||
new Dictionary<string, object>
|
||||
{
|
||||
{
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
|
||||
},
|
||||
{
|
||||
"total", user.UsedSlots
|
||||
|
@ -135,7 +135,7 @@ public class SlotsController : ControllerBase
|
|||
new Dictionary<string, object>
|
||||
{
|
||||
{
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
|
||||
},
|
||||
{
|
||||
"total", await StatisticsHelper.SlotCount()
|
||||
|
@ -169,7 +169,7 @@ public class SlotsController : ControllerBase
|
|||
new Dictionary<string, object>
|
||||
{
|
||||
{
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
|
||||
},
|
||||
{
|
||||
"total", await StatisticsHelper.TeamPickCount()
|
||||
|
@ -200,7 +200,7 @@ public class SlotsController : ControllerBase
|
|||
new Dictionary<string, object>
|
||||
{
|
||||
{
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
|
||||
},
|
||||
{
|
||||
"total", await StatisticsHelper.SlotCount()
|
||||
|
@ -244,7 +244,7 @@ public class SlotsController : ControllerBase
|
|||
new Dictionary<string, object>
|
||||
{
|
||||
{
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
|
||||
},
|
||||
{
|
||||
"total", await StatisticsHelper.SlotCount()
|
||||
|
@ -302,7 +302,7 @@ public class SlotsController : ControllerBase
|
|||
new Dictionary<string, object>
|
||||
{
|
||||
{
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
|
||||
},
|
||||
{
|
||||
"total", await StatisticsHelper.SlotCount()
|
||||
|
@ -346,7 +346,7 @@ public class SlotsController : ControllerBase
|
|||
new Dictionary<string, object>
|
||||
{
|
||||
{
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
|
||||
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
|
||||
},
|
||||
{
|
||||
"total", await StatisticsHelper.SlotCount()
|
||||
|
@ -403,4 +403,4 @@ public class SlotsController : ControllerBase
|
|||
|
||||
return whereSlots.Include(s => s.Creator).Include(s => s.Location);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ public class Database : DbContext
|
|||
public DbSet<EmailSetToken> EmailSetTokens { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||
=> options.UseMySql(ServerSettings.Instance.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion);
|
||||
=> options.UseMySql(ServerConfiguration.Instance.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion);
|
||||
|
||||
#nullable enable
|
||||
public async Task<User> CreateUser(string username, string password, string? emailAddress = null)
|
||||
|
@ -82,10 +82,10 @@ public class Database : DbContext
|
|||
|
||||
await this.SaveChangesAsync();
|
||||
|
||||
if (emailAddress != null && ServerSettings.Instance.SMTPEnabled)
|
||||
if (emailAddress != null && ServerConfiguration.Instance.Mail.MailEnabled)
|
||||
{
|
||||
string body = "An account for Project Lighthouse has been registered with this email address.\n\n" +
|
||||
$"You can login at {ServerSettings.Instance.ExternalUrl}.";
|
||||
$"You can login at {ServerConfiguration.Instance.ExternalUrl}.";
|
||||
|
||||
SMTPHelper.SendEmail(emailAddress, "Project Lighthouse Account Created: " + username, body);
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@ public static class CaptchaHelper
|
|||
[SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeNotEvident")]
|
||||
public static async Task<bool> Verify(string token)
|
||||
{
|
||||
if (!ServerSettings.Instance.HCaptchaEnabled) return true;
|
||||
if (!ServerConfiguration.Instance.Captcha.CaptchaEnabled) return true;
|
||||
|
||||
List<KeyValuePair<string, string>> payload = new()
|
||||
{
|
||||
new("secret", ServerSettings.Instance.HCaptchaSecret),
|
||||
new("secret", ServerConfiguration.Instance.Captcha.Secret),
|
||||
new("response", token),
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ public static class CensorHelper
|
|||
|
||||
public static string ScanMessage(string message)
|
||||
{
|
||||
if (ServerSettings.Instance.UserInputFilterMode == FilterMode.None) return message;
|
||||
if (ServerConfiguration.Instance.UserInputFilterMode == FilterMode.None) return message;
|
||||
|
||||
int profaneIndex = -1;
|
||||
|
||||
|
@ -44,7 +44,7 @@ public static class CensorHelper
|
|||
|
||||
sb.Append(message.AsSpan(0, profanityIndex));
|
||||
|
||||
switch (ServerSettings.Instance.UserInputFilterMode)
|
||||
switch (ServerConfiguration.Instance.UserInputFilterMode)
|
||||
{
|
||||
case FilterMode.Random:
|
||||
for(int i = 0; i < profanityLength; i++)
|
||||
|
|
|
@ -26,7 +26,7 @@ public static class RequestExtensions
|
|||
|
||||
public static async Task<bool> CheckCaptchaValidity(this HttpRequest request)
|
||||
{
|
||||
if (ServerSettings.Instance.HCaptchaEnabled)
|
||||
if (ServerConfiguration.Instance.Captcha.CaptchaEnabled)
|
||||
{
|
||||
bool gotCaptcha = request.Form.TryGetValue("h-captcha-response", out StringValues values);
|
||||
if (!gotCaptcha) return false;
|
||||
|
|
|
@ -20,7 +20,7 @@ public static class FileHelper
|
|||
|
||||
public static bool IsFileSafe(LbpFile file)
|
||||
{
|
||||
if (!ServerSettings.Instance.CheckForUnsafeFiles) return true;
|
||||
if (!ServerConfiguration.Instance.CheckForUnsafeFiles) return true;
|
||||
|
||||
if (file.FileType == LbpFileType.Unknown) return false;
|
||||
|
||||
|
|
|
@ -14,7 +14,8 @@ namespace LBPUnion.ProjectLighthouse.Helpers;
|
|||
|
||||
public static class InfluxHelper
|
||||
{
|
||||
public static readonly InfluxDBClient Client = InfluxDBClientFactory.Create(ServerSettings.Instance.InfluxUrl, ServerSettings.Instance.InfluxToken);
|
||||
public static readonly InfluxDBClient Client = InfluxDBClientFactory.Create
|
||||
(url: ServerConfiguration.Instance.InfluxDB.Url, token: ServerConfiguration.Instance.InfluxDB.Token);
|
||||
|
||||
private static readonly List<GameVersion> gameVersions = new()
|
||||
{
|
||||
|
@ -40,10 +41,10 @@ public static class InfluxHelper
|
|||
.Tag("game", gameVersion.ToString())
|
||||
.Field("playerCountGame", await StatisticsHelper.RecentMatchesForGame(gameVersion));
|
||||
|
||||
writeApi.WritePoint(gamePoint, ServerSettings.Instance.InfluxBucket, ServerSettings.Instance.InfluxOrg);
|
||||
writeApi.WritePoint(gamePoint, ServerConfiguration.Instance.InfluxDB.Bucket, ServerConfiguration.Instance.InfluxDB.Organization);
|
||||
}
|
||||
|
||||
writeApi.WritePoint(point, ServerSettings.Instance.InfluxBucket, ServerSettings.Instance.InfluxOrg);
|
||||
writeApi.WritePoint(point, ServerConfiguration.Instance.InfluxDB.Bucket, ServerConfiguration.Instance.InfluxDB.Organization);
|
||||
|
||||
writeApi.Flush();
|
||||
}
|
||||
|
|
|
@ -12,20 +12,20 @@ public static class SMTPHelper
|
|||
|
||||
static SMTPHelper()
|
||||
{
|
||||
if (!ServerSettings.Instance.SMTPEnabled) return;
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return;
|
||||
|
||||
client = new SmtpClient(ServerSettings.Instance.SMTPHost, ServerSettings.Instance.SMTPPort)
|
||||
client = new SmtpClient(ServerConfiguration.Instance.Mail.Host, ServerConfiguration.Instance.Mail.Port)
|
||||
{
|
||||
EnableSsl = ServerSettings.Instance.SMTPSsl,
|
||||
Credentials = new NetworkCredential(ServerSettings.Instance.SMTPFromAddress, ServerSettings.Instance.SMTPPassword),
|
||||
EnableSsl = ServerConfiguration.Instance.Mail.UseSSL,
|
||||
Credentials = new NetworkCredential(ServerConfiguration.Instance.Mail.FromAddress, ServerConfiguration.Instance.Mail.Password),
|
||||
};
|
||||
|
||||
fromAddress = new MailAddress(ServerSettings.Instance.SMTPFromAddress, ServerSettings.Instance.SMTPFromName);
|
||||
fromAddress = new MailAddress(ServerConfiguration.Instance.Mail.FromAddress, ServerConfiguration.Instance.Mail.FromName);
|
||||
}
|
||||
|
||||
public static bool SendEmail(string recipientAddress, string subject, string body)
|
||||
{
|
||||
if (!ServerSettings.Instance.SMTPEnabled) return false;
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return false;
|
||||
|
||||
MailMessage message = new(fromAddress, new MailAddress(recipientAddress))
|
||||
{
|
||||
|
|
|
@ -7,14 +7,17 @@ namespace LBPUnion.ProjectLighthouse.Helpers;
|
|||
|
||||
public static class WebhookHelper
|
||||
{
|
||||
private static readonly DiscordWebhookClient client = (ServerSettings.Instance.DiscordWebhookEnabled ? new DiscordWebhookClient(ServerSettings.Instance.DiscordWebhookUrl) : null);
|
||||
private static readonly DiscordWebhookClient client = (ServerConfiguration.Instance.DiscordIntegration.DiscordIntegrationEnabled
|
||||
? new DiscordWebhookClient(ServerConfiguration.Instance.DiscordIntegration.Url)
|
||||
: null);
|
||||
|
||||
public static readonly Color UnionColor = new(0, 140, 255);
|
||||
|
||||
public static Task SendWebhook(EmbedBuilder builder) => SendWebhook(builder.Build());
|
||||
|
||||
public static async Task SendWebhook(Embed embed)
|
||||
{
|
||||
if (!ServerSettings.Instance.DiscordWebhookEnabled) return;
|
||||
if (!ServerConfiguration.Instance.DiscordIntegration.DiscordIntegrationEnabled) return;
|
||||
|
||||
await client.SendMessageAsync
|
||||
(
|
||||
|
|
|
@ -18,6 +18,6 @@ public class InfluxLogger : ILogger
|
|||
|
||||
PointData point = PointData.Measurement("lighthouseLog").Field("level", level).Field("content", content);
|
||||
|
||||
writeApi.WritePoint(point, ServerSettings.Instance.InfluxBucket, ServerSettings.Instance.InfluxOrg);
|
||||
writeApi.WritePoint(point, ServerConfiguration.Instance.InfluxDB.Bucket, ServerConfiguration.Instance.InfluxDB.Organization);
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ public class CompleteEmailVerificationPage : BaseLayout
|
|||
|
||||
public async Task<IActionResult> OnGet(string token)
|
||||
{
|
||||
if (!ServerSettings.Instance.SMTPEnabled) return this.NotFound();
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
||||
|
||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("~/login");
|
||||
|
|
|
@ -21,7 +21,7 @@ public class AuthenticationPage : BaseLayout
|
|||
|
||||
public IActionResult OnGet()
|
||||
{
|
||||
if (!ServerSettings.Instance.UseExternalAuth) return this.NotFound();
|
||||
if (!ServerConfiguration.Instance.Authentication.UseExternalAuth) return this.NotFound();
|
||||
if (this.User == null) return this.StatusCode(403, "");
|
||||
|
||||
this.IpAddress = this.HttpContext.Connection.RemoteIpAddress;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
@if (Model.User != null)
|
||||
{
|
||||
<p>You are currently logged in as <b>@Model.User.Username</b>.</p>
|
||||
if (ServerSettings.Instance.UseExternalAuth && Model.AuthenticationAttemptsCount > 0)
|
||||
if (ServerConfiguration.Instance.Authentication.UseExternalAuth && Model.AuthenticationAttemptsCount > 0)
|
||||
{
|
||||
<p>
|
||||
<b>You have @Model.AuthenticationAttemptsCount authentication attempts pending. Click <a href="/authentication">here</a> to view them.</b>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
if (ServerSettings.Instance.UseExternalAuth)
|
||||
if (ServerConfiguration.Instance.Authentication.UseExternalAuth)
|
||||
{
|
||||
Model.NavigationItems.Add(new PageNavigationItem("Authentication", "/authentication", "key"));
|
||||
}
|
||||
|
@ -62,16 +62,16 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
@* Google Analytics *@
|
||||
@if (ServerSettings.Instance.GoogleAnalyticsEnabled)
|
||||
@if (ServerConfiguration.Instance.GoogleAnalytics.AnalyticsEnabled)
|
||||
{
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=@ServerSettings.Instance.GoogleAnalyticsId"></script>
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=@ServerConfiguration.Instance.GoogleAnalytics.Id"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', '@ServerSettings.Instance.GoogleAnalyticsId');
|
||||
gtag('config', '@ServerConfiguration.Instance.GoogleAnalytics.Id');
|
||||
</script>
|
||||
}
|
||||
</head>
|
||||
|
|
|
@ -50,13 +50,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
@if (ServerSettings.Instance.HCaptchaEnabled)
|
||||
@if (ServerConfiguration.Instance.Captcha.CaptchaEnabled)
|
||||
{
|
||||
@await Html.PartialAsync("Partials/CaptchaPartial")
|
||||
}
|
||||
|
||||
<input type="submit" value="Log in" id="submit" class="ui blue button">
|
||||
@if (ServerSettings.Instance.RegistrationEnabled)
|
||||
@if (ServerConfiguration.Instance.Authentication.RegistrationEnabled)
|
||||
{
|
||||
<a href="/register">
|
||||
<div class="ui button">
|
||||
|
|
|
@ -65,7 +65,7 @@ public class LoginForm : BaseLayout
|
|||
return this.Page();
|
||||
}
|
||||
|
||||
if (user.EmailAddress == null && ServerSettings.Instance.SMTPEnabled)
|
||||
if (user.EmailAddress == null && ServerConfiguration.Instance.Mail.MailEnabled)
|
||||
{
|
||||
Logger.LogWarn($"User {user.Username} (id: {user.UserId}) failed to login; email not set", LogArea.Login);
|
||||
|
||||
|
@ -104,7 +104,7 @@ public class LoginForm : BaseLayout
|
|||
Logger.LogSuccess($"User {user.Username} (id: {user.UserId}) successfully logged in on web", LogArea.Login);
|
||||
|
||||
if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
|
||||
if (ServerSettings.Instance.SMTPEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
|
||||
if (ServerConfiguration.Instance.Mail.MailEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
|
||||
|
||||
return this.RedirectToPage(nameof(LandingPage));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@using LBPUnion.ProjectLighthouse.Types.Settings
|
||||
@if (ServerSettings.Instance.HCaptchaEnabled)
|
||||
@if (ServerConfiguration.Instance.Captcha.CaptchaEnabled)
|
||||
{
|
||||
<div class="h-captcha" data-sitekey="@ServerSettings.Instance.HCaptchaSiteKey"></div>
|
||||
<div class="h-captcha" data-sitekey="@ServerConfiguration.Instance.Captcha.SiteKey"></div>
|
||||
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
bool showLink = (bool?)ViewData["ShowLink"] ?? false;
|
||||
|
||||
string iconHash = Model.IconHash;
|
||||
if (string.IsNullOrWhiteSpace(iconHash) || iconHash.StartsWith('g')) iconHash = ServerSettings.Instance.MissingIconHash;
|
||||
if (string.IsNullOrWhiteSpace(iconHash) || iconHash.StartsWith('g')) iconHash = ServerConfiguration.Instance.WebsiteConfiguration.MissingIconHash;
|
||||
}
|
||||
<div class="card">
|
||||
@{
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
@if (ServerSettings.Instance.SMTPEnabled)
|
||||
@if (ServerConfiguration.Instance.Mail.MailEnabled)
|
||||
{
|
||||
<div class="field">
|
||||
<label>Email address</label>
|
||||
|
@ -72,7 +72,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
@if (ServerSettings.Instance.HCaptchaEnabled)
|
||||
@if (ServerConfiguration.Instance.Captcha.CaptchaEnabled)
|
||||
{
|
||||
@await Html.PartialAsync("Partials/CaptchaPartial")
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public class RegisterForm : BaseLayout
|
|||
[SuppressMessage("ReSharper", "SpecifyStringComparison")]
|
||||
public async Task<IActionResult> OnPost(string username, string password, string confirmPassword, string emailAddress)
|
||||
{
|
||||
if (!ServerSettings.Instance.RegistrationEnabled) return this.NotFound();
|
||||
if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled) return this.NotFound();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ public class RegisterForm : BaseLayout
|
|||
return this.Page();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(emailAddress) && ServerSettings.Instance.SMTPEnabled)
|
||||
if (string.IsNullOrWhiteSpace(emailAddress) && ServerConfiguration.Instance.Mail.MailEnabled)
|
||||
{
|
||||
this.Error = "Email address field is required.";
|
||||
return this.Page();
|
||||
|
@ -54,7 +54,7 @@ public class RegisterForm : BaseLayout
|
|||
return this.Page();
|
||||
}
|
||||
|
||||
if (ServerSettings.Instance.SMTPEnabled &&
|
||||
if (ServerConfiguration.Instance.Mail.MailEnabled &&
|
||||
await this.Database.Users.FirstOrDefaultAsync(u => u.EmailAddress.ToLower() == emailAddress.ToLower()) != null)
|
||||
{
|
||||
this.Error = "The email address you've chosen is already taken.";
|
||||
|
@ -80,7 +80,7 @@ public class RegisterForm : BaseLayout
|
|||
|
||||
this.Response.Cookies.Append("LighthouseToken", webToken.UserToken);
|
||||
|
||||
if (ServerSettings.Instance.SMTPEnabled) return this.Redirect("~/login/sendVerificationEmail");
|
||||
if (ServerConfiguration.Instance.Mail.MailEnabled) return this.Redirect("~/login/sendVerificationEmail");
|
||||
|
||||
return this.RedirectToPage(nameof(LandingPage));
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ public class RegisterForm : BaseLayout
|
|||
public IActionResult OnGet()
|
||||
{
|
||||
this.Error = string.Empty;
|
||||
if (!ServerSettings.Instance.RegistrationEnabled) return this.NotFound();
|
||||
if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled) return this.NotFound();
|
||||
|
||||
return this.Page();
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ public class SendVerificationEmailPage : BaseLayout
|
|||
|
||||
public async Task<IActionResult> OnGet()
|
||||
{
|
||||
if (!ServerSettings.Instance.SMTPEnabled) return this.NotFound();
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
||||
|
||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("/login");
|
||||
|
@ -47,7 +47,7 @@ public class SendVerificationEmailPage : BaseLayout
|
|||
|
||||
string body = "Hello,\n\n" +
|
||||
$"This email is a request to verify this email for your (likely new!) Project Lighthouse account ({user.Username}).\n\n" +
|
||||
$"To verify your account, click the following link: {ServerSettings.Instance.ExternalUrl}/verifyEmail?token={verifyToken.EmailToken}\n\n\n" +
|
||||
$"To verify your account, click the following link: {ServerConfiguration.Instance.ExternalUrl}/verifyEmail?token={verifyToken.EmailToken}\n\n\n" +
|
||||
"If this wasn't you, feel free to ignore this email.";
|
||||
|
||||
if (SMTPHelper.SendEmail(user.EmailAddress, "Project Lighthouse Email Verification", body))
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<form class="ui form" onsubmit="return onSubmit(this)" method="post">
|
||||
@Html.AntiForgeryToken()
|
||||
|
||||
@if (ServerSettings.Instance.SMTPEnabled)
|
||||
@if (ServerConfiguration.Instance.Mail.MailEnabled)
|
||||
{
|
||||
<div class="field">
|
||||
<label>Please type a valid email address and verify it:</label>
|
||||
|
|
|
@ -22,7 +22,7 @@ public class SetEmailForm : BaseLayout
|
|||
|
||||
public async Task<IActionResult> OnGet(string? token = null)
|
||||
{
|
||||
if (!ServerSettings.Instance.SMTPEnabled) return this.NotFound();
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
||||
if (token == null) return this.Redirect("/login");
|
||||
|
||||
EmailSetToken? emailToken = await this.Database.EmailSetTokens.FirstOrDefaultAsync(t => t.EmailToken == token);
|
||||
|
@ -35,7 +35,7 @@ public class SetEmailForm : BaseLayout
|
|||
|
||||
public async Task<IActionResult> OnPost(string emailAddress, string token)
|
||||
{
|
||||
if (!ServerSettings.Instance.SMTPEnabled) return this.NotFound();
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
||||
|
||||
EmailSetToken? emailToken = await this.Database.EmailSetTokens.Include(t => t.User).FirstOrDefaultAsync(t => t.EmailToken == token);
|
||||
if (emailToken == null) return this.Redirect("/login");
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
}
|
||||
<div class="ui divider"></div>
|
||||
|
||||
@for (int i = 0; i < Model.Reviews.Count; i++)
|
||||
@for(int i = 0; i < Model.Reviews.Count; i++)
|
||||
{
|
||||
Review review = Model.Reviews[i];
|
||||
string faceHash = review.Thumb switch {
|
||||
|
@ -95,10 +95,9 @@
|
|||
|
||||
if (string.IsNullOrWhiteSpace(faceHash))
|
||||
{
|
||||
faceHash = ServerSettings.Instance.MissingIconHash;
|
||||
faceHash = ServerConfiguration.Instance.WebsiteConfiguration.MissingIconHash;
|
||||
}
|
||||
|
||||
|
||||
string faceAlt = review.Thumb switch {
|
||||
-1 => "Boo!",
|
||||
0 => "Meh.",
|
||||
|
@ -111,7 +110,7 @@
|
|||
|
||||
<div class="card">
|
||||
<div>
|
||||
<img class="cardIcon slotCardIcon" src="@ServerSettings.Instance.ExternalUrl/gameAssets/@faceHash" alt="@faceAlt" title="@faceAlt" style="min-width: @(size)px; width: @(size)px; height: @(size)px">
|
||||
<img class="cardIcon slotCardIcon" src="@ServerConfiguration.Instance.ExternalUrl/gameAssets/@faceHash" alt="@faceAlt" title="@faceAlt" style="min-width: @(size)px; width: @(size)px; height: @(size)px">
|
||||
</div>
|
||||
<div class="cardStats">
|
||||
<h3 style="margin-bottom: 5px;">@review.Reviewer?.Username</h3>
|
||||
|
|
|
@ -18,8 +18,8 @@ public class SlotPage : BaseLayout
|
|||
public List<Comment> Comments = new();
|
||||
public List<Review> Reviews = new();
|
||||
|
||||
public readonly bool CommentsEnabled = ServerSettings.Instance.LevelCommentsEnabled;
|
||||
public readonly bool ReviewsEnabled = ServerSettings.Instance.LevelReviewsEnabled;
|
||||
public readonly bool CommentsEnabled = ServerConfiguration.Instance.UserGeneratedContentLimits.LevelCommentsEnabled;
|
||||
public readonly bool ReviewsEnabled = ServerConfiguration.Instance.UserGeneratedContentLimits.LevelReviewsEnabled;
|
||||
|
||||
public Slot? Slot;
|
||||
public SlotPage(Database database) : base(database)
|
||||
|
|
|
@ -15,7 +15,7 @@ public class UserPage : BaseLayout
|
|||
{
|
||||
public List<Comment>? Comments;
|
||||
|
||||
public bool CommentsEnabled = ServerSettings.Instance.ProfileCommentsEnabled;
|
||||
public bool CommentsEnabled = ServerConfiguration.Instance.UserGeneratedContentLimits.ProfileCommentsEnabled;
|
||||
|
||||
public bool IsProfileUserHearted;
|
||||
|
||||
|
@ -45,15 +45,16 @@ public class UserPage : BaseLayout
|
|||
}
|
||||
|
||||
if (this.User == null) return this.Page();
|
||||
|
||||
|
||||
foreach (Comment c in this.Comments)
|
||||
{
|
||||
Reaction? reaction = await this.Database.Reactions.FirstOrDefaultAsync(r => r.UserId == this.User.UserId && r.TargetId == c.CommentId);
|
||||
if (reaction != null) c.YourThumb = reaction.Rating;
|
||||
Reaction? reaction = await this.Database.Reactions.FirstOrDefaultAsync(r => r.UserId == this.User.UserId && r.TargetId == c.CommentId);
|
||||
if (reaction != null) c.YourThumb = reaction.Rating;
|
||||
}
|
||||
this.IsProfileUserHearted = await this.Database.HeartedProfiles.FirstOrDefaultAsync
|
||||
(u => u.UserId == this.User.UserId && u.HeartedUserId == this.ProfileUser.UserId) != null;
|
||||
(u => u.UserId == this.User.UserId && u.HeartedUserId == this.ProfileUser.UserId) !=
|
||||
null;
|
||||
|
||||
return this.Page();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ public static class Program
|
|||
Logger.LogInfo($"You are running version {VersionHelper.FullVersion}", LogArea.Startup);
|
||||
|
||||
// Referencing ServerSettings.Instance here loads the config, see ServerSettings.cs for more information
|
||||
Logger.LogSuccess("Loaded config file version " + ServerSettings.Instance.ConfigVersion, LogArea.Startup);
|
||||
Logger.LogSuccess("Loaded config file version " + ServerConfiguration.Instance.ConfigVersion, LogArea.Startup);
|
||||
|
||||
Logger.LogInfo("Determining if the database is available...", LogArea.Startup);
|
||||
bool dbConnected = ServerStatics.DbConnected;
|
||||
|
@ -50,11 +50,11 @@ public static class Program
|
|||
Logger.LogInfo("Migrating database...", LogArea.Database);
|
||||
MigrateDatabase(database);
|
||||
|
||||
if (ServerSettings.Instance.InfluxEnabled)
|
||||
if (ServerConfiguration.Instance.InfluxDB.InfluxEnabled)
|
||||
{
|
||||
Logger.LogInfo("Influx logging is enabled. Starting influx logging...", LogArea.Startup);
|
||||
InfluxHelper.StartLogging().Wait();
|
||||
if (ServerSettings.Instance.InfluxLoggingEnabled) Logger.AddLogger(new InfluxLogger());
|
||||
if (ServerConfiguration.Instance.InfluxDB.LoggingEnabled) Logger.AddLogger(new InfluxLogger());
|
||||
}
|
||||
|
||||
Logger.LogDebug
|
||||
|
@ -72,7 +72,7 @@ public static class Program
|
|||
return;
|
||||
}
|
||||
|
||||
if (ServerSettings.Instance.ConvertAssetsOnStartup) FileHelper.ConvertAllTexturesToPng();
|
||||
if (ServerConfiguration.Instance.WebsiteConfiguration.ConvertAssetsOnStartup) FileHelper.ConvertAllTexturesToPng();
|
||||
|
||||
Logger.LogInfo("Starting room cleanup thread...", LogArea.Startup);
|
||||
RoomHelper.StartCleanupThread();
|
||||
|
@ -102,7 +102,7 @@ public static class Program
|
|||
{
|
||||
webBuilder.UseStartup<Startup.Startup>();
|
||||
webBuilder.UseWebRoot("StaticFiles");
|
||||
webBuilder.UseUrls(ServerSettings.Instance.ServerListenUrl);
|
||||
webBuilder.UseUrls(ServerConfiguration.Instance.ListenUrl);
|
||||
}
|
||||
)
|
||||
.ConfigureLogging
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1"/>
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3"/>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1"/>
|
||||
<PackageReference Include="YamlDotNet" Version="11.2.1"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -52,6 +53,7 @@
|
|||
</EmbeddedResource>
|
||||
<None Remove="recent-activity.xml" />
|
||||
<None Remove="r.tar.gz" />
|
||||
<None Remove="lighthouse.yml"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -37,7 +37,7 @@ public class DebugWarmupLifetime : IHostLifetime
|
|||
{
|
||||
using HttpClient client = new();
|
||||
|
||||
string url = ServerSettings.Instance.ServerListenUrl;
|
||||
string url = ServerConfiguration.Instance.ListenUrl;
|
||||
url = url.Replace("0.0.0.0", "127.0.0.1");
|
||||
|
||||
Logger.LogDebug("Warming up Hot Reload...", LogArea.Startup);
|
||||
|
|
|
@ -96,7 +96,7 @@ public class Startup
|
|||
{
|
||||
bool computeDigests = true;
|
||||
|
||||
if (string.IsNullOrEmpty(ServerSettings.Instance.ServerDigestKey))
|
||||
if (string.IsNullOrEmpty(ServerConfiguration.Instance.DigestKey.PrimaryDigestKey))
|
||||
{
|
||||
Logger.LogWarn
|
||||
(
|
||||
|
@ -172,7 +172,8 @@ public class Startup
|
|||
|
||||
if (computeDigests && digestPath.StartsWith("/LITTLEBIGPLANETPS3_XML"))
|
||||
{
|
||||
string clientRequestDigest = await CryptoHelper.ComputeDigest(digestPath, authCookie, body, ServerSettings.Instance.ServerDigestKey);
|
||||
string clientRequestDigest = await CryptoHelper.ComputeDigest
|
||||
(digestPath, authCookie, body, ServerConfiguration.Instance.DigestKey.PrimaryDigestKey);
|
||||
|
||||
// Check the digest we've just calculated against the X-Digest-A header if the game set the header. They should match.
|
||||
if (context.Request.Headers.TryGetValue("X-Digest-A", out StringValues sentDigest))
|
||||
|
@ -185,13 +186,14 @@ public class Startup
|
|||
// Reset the body stream
|
||||
body.Position = 0;
|
||||
|
||||
clientRequestDigest = await CryptoHelper.ComputeDigest(digestPath, authCookie, body, ServerSettings.Instance.AlternateDigestKey);
|
||||
clientRequestDigest = await CryptoHelper.ComputeDigest
|
||||
(digestPath, authCookie, body, ServerConfiguration.Instance.DigestKey.AlternateDigestKey);
|
||||
if (clientRequestDigest != sentDigest)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine("Digest failed");
|
||||
Console.WriteLine("digestKey: " + ServerSettings.Instance.ServerDigestKey);
|
||||
Console.WriteLine("altDigestKey: " + ServerSettings.Instance.AlternateDigestKey);
|
||||
Console.WriteLine("digestKey: " + ServerConfiguration.Instance.DigestKey.PrimaryDigestKey);
|
||||
Console.WriteLine("altDigestKey: " + ServerConfiguration.Instance.DigestKey.AlternateDigestKey);
|
||||
Console.WriteLine("computed digest: " + clientRequestDigest);
|
||||
#endif
|
||||
// We still failed to validate. Abort the request.
|
||||
|
@ -218,7 +220,9 @@ public class Startup
|
|||
{
|
||||
responseBuffer.Position = 0;
|
||||
|
||||
string digestKey = usedAlternateDigestKey ? ServerSettings.Instance.AlternateDigestKey : ServerSettings.Instance.ServerDigestKey;
|
||||
string digestKey = usedAlternateDigestKey
|
||||
? ServerConfiguration.Instance.DigestKey.AlternateDigestKey
|
||||
: ServerConfiguration.Instance.DigestKey.PrimaryDigestKey;
|
||||
|
||||
// Compute the digest for the response.
|
||||
string serverDigest = await CryptoHelper.ComputeDigest(context.Request.Path, authCookie, responseBuffer, digestKey);
|
||||
|
|
|
@ -289,8 +289,8 @@ public class Slot
|
|||
LbpSerializer.StringElement("yourlbpPlayCount", yourVisitedStats?.PlaysLBP1) +
|
||||
LbpSerializer.StringElement("yourlbp3PlayCount", yourVisitedStats?.PlaysLBP3) +
|
||||
yourReview?.Serialize("yourReview") +
|
||||
LbpSerializer.StringElement("reviewsEnabled", ServerSettings.Instance.LevelReviewsEnabled) +
|
||||
LbpSerializer.StringElement("commentsEnabled", ServerSettings.Instance.LevelCommentsEnabled) +
|
||||
LbpSerializer.StringElement("reviewsEnabled", ServerConfiguration.Instance.UserGeneratedContentLimits.LevelReviewsEnabled) +
|
||||
LbpSerializer.StringElement("commentsEnabled", ServerConfiguration.Instance.UserGeneratedContentLimits.LevelCommentsEnabled) +
|
||||
LbpSerializer.StringElement("playerCount", playerCount) +
|
||||
LbpSerializer.StringElement("reviewCount", this.ReviewCount);
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
public class AuthenticationConfiguration
|
||||
{
|
||||
public bool BlockDeniedUsers { get; set; } = true;
|
||||
public bool RegistrationEnabled { get; set; } = true;
|
||||
public bool UseExternalAuth { get; set; }
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
public class CaptchaConfiguration
|
||||
{
|
||||
// TODO: support recaptcha, not just hcaptcha
|
||||
// use an enum to define which captcha services can be used?
|
||||
// LBPUnion.ProjectLighthouse.Types.Settings.CaptchaService
|
||||
public bool CaptchaEnabled { get; set; }
|
||||
|
||||
public string SiteKey { get; set; } = "";
|
||||
|
||||
public string Secret { get; set; } = "";
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
public class DigestKeyConfiguration
|
||||
{
|
||||
// todo: move to list?
|
||||
public string PrimaryDigestKey { get; set; } = "";
|
||||
public string AlternateDigestKey { get; set; } = "";
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#nullable enable
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
public class DiscordIntegrationConfiguration
|
||||
{
|
||||
//TODO: integrations should be modular/abstracted away
|
||||
|
||||
public bool DiscordIntegrationEnabled { get; set; }
|
||||
|
||||
public string Url { get; set; } = "";
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
public class GoogleAnalyticsConfiguration
|
||||
{
|
||||
public bool AnalyticsEnabled { get; set; }
|
||||
|
||||
public string Id { get; set; } = "";
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
public class InfluxDBConfiguration
|
||||
{
|
||||
public bool InfluxEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to log to InfluxDB.
|
||||
/// </summary>
|
||||
public bool LoggingEnabled { get; set; }
|
||||
|
||||
public string Organization { get; set; } = "lighthouse";
|
||||
public string Bucket { get; set; } = "lighthouse";
|
||||
public string Token { get; set; } = "";
|
||||
public string Url { get; set; } = "http://localhost:8086";
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
public class MailConfiguration
|
||||
{
|
||||
public bool MailEnabled { get; set; }
|
||||
|
||||
public string Host { get; set; } = "";
|
||||
|
||||
public int Port { get; set; } = 587;
|
||||
|
||||
public string FromAddress { get; set; } = "lighthouse@example.com";
|
||||
|
||||
public string FromName { get; set; } = "Project Lighthouse";
|
||||
|
||||
public string Password { get; set; } = "";
|
||||
|
||||
public bool UseSSL { get; set; } = true;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
public class UserGeneratedContentLimitConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum amount of slots allowed on users' earth
|
||||
/// </summary>
|
||||
public int EntitledSlots { get; set; } = 50;
|
||||
|
||||
public int ListsQuota { get; set; } = 50;
|
||||
|
||||
public int PhotosQuota { get; set; } = 500;
|
||||
|
||||
public bool ProfileCommentsEnabled { get; set; } = true;
|
||||
|
||||
public bool LevelCommentsEnabled { get; set; } = true;
|
||||
|
||||
public bool LevelReviewsEnabled { get; set; } = true;
|
||||
|
||||
public bool BooingEnabled { get; set; } = true;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
public class WebsiteConfiguration
|
||||
{
|
||||
public string MissingIconHash { get; set; } = "";
|
||||
|
||||
public bool ConvertAssetsOnStartup { get; set; } = true;
|
||||
}
|
214
ProjectLighthouse/Types/Settings/Legacy/LegacyServerSettings.cs
Normal file
214
ProjectLighthouse/Types/Settings/Legacy/LegacyServerSettings.cs
Normal file
|
@ -0,0 +1,214 @@
|
|||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Settings.Legacy;
|
||||
#nullable enable
|
||||
|
||||
internal class LegacyServerSettings
|
||||
{
|
||||
|
||||
#region Meta
|
||||
|
||||
public const string ConfigFileName = "lighthouse.config.json";
|
||||
|
||||
#endregion
|
||||
|
||||
#region InfluxDB
|
||||
|
||||
public bool InfluxEnabled { get; set; }
|
||||
public bool InfluxLoggingEnabled { get; set; }
|
||||
public string InfluxOrg { get; set; } = "lighthouse";
|
||||
public string InfluxBucket { get; set; } = "lighthouse";
|
||||
public string InfluxToken { get; set; } = "";
|
||||
public string InfluxUrl { get; set; } = "http://localhost:8086";
|
||||
|
||||
#endregion
|
||||
|
||||
public string EulaText { get; set; } = "";
|
||||
|
||||
#if !DEBUG
|
||||
public string AnnounceText { get; set; } = "You are now logged in as %user.";
|
||||
#else
|
||||
public string AnnounceText { get; set; } = "You are now logged in as %user (id: %id).";
|
||||
#endif
|
||||
|
||||
public string DbConnectionString { get; set; } = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse";
|
||||
|
||||
public string ExternalUrl { get; set; } = "http://localhost:10060";
|
||||
public string ServerDigestKey { get; set; } = "";
|
||||
public string AlternateDigestKey { get; set; } = "";
|
||||
public bool UseExternalAuth { get; set; }
|
||||
|
||||
public bool CheckForUnsafeFiles { get; set; } = true;
|
||||
|
||||
public bool RegistrationEnabled { get; set; } = true;
|
||||
|
||||
#region UGC Limits
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount of slots allowed on users' earth
|
||||
/// </summary>
|
||||
public int EntitledSlots { get; set; } = 50;
|
||||
|
||||
public int ListsQuota { get; set; } = 50;
|
||||
|
||||
public int PhotosQuota { get; set; } = 500;
|
||||
|
||||
public bool ProfileCommentsEnabled { get; set; } = true;
|
||||
|
||||
public bool LevelCommentsEnabled { get; set; } = true;
|
||||
|
||||
public bool LevelReviewsEnabled { get; set; } = true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Google Analytics
|
||||
|
||||
public bool GoogleAnalyticsEnabled { get; set; }
|
||||
|
||||
public string GoogleAnalyticsId { get; set; } = "";
|
||||
|
||||
#endregion
|
||||
|
||||
public bool BlockDeniedUsers { get; set; } = true;
|
||||
|
||||
public bool BooingEnabled { get; set; } = true;
|
||||
|
||||
public FilterMode UserInputFilterMode { get; set; } = FilterMode.None;
|
||||
|
||||
#region Discord Webhook
|
||||
|
||||
public bool DiscordWebhookEnabled { get; set; }
|
||||
|
||||
public string DiscordWebhookUrl { get; set; } = "";
|
||||
|
||||
#endregion
|
||||
|
||||
public bool ConfigReloading { get; set; } = true;
|
||||
|
||||
public string MissingIconHash { get; set; } = "";
|
||||
|
||||
#region HCaptcha
|
||||
|
||||
public bool HCaptchaEnabled { get; set; }
|
||||
|
||||
public string HCaptchaSiteKey { get; set; } = "";
|
||||
|
||||
public string HCaptchaSecret { get; set; } = "";
|
||||
|
||||
#endregion
|
||||
|
||||
public string ServerListenUrl { get; set; } = "http://localhost:10060";
|
||||
|
||||
public bool ConvertAssetsOnStartup { get; set; } = true;
|
||||
|
||||
#region SMTP
|
||||
|
||||
public bool SMTPEnabled { get; set; }
|
||||
|
||||
public string SMTPHost { get; set; } = "";
|
||||
|
||||
public int SMTPPort { get; set; } = 587;
|
||||
|
||||
public string SMTPFromAddress { get; set; } = "lighthouse@example.com";
|
||||
|
||||
public string SMTPFromName { get; set; } = "Project Lighthouse";
|
||||
|
||||
public string SMTPPassword { get; set; } = "";
|
||||
|
||||
public bool SMTPSsl { get; set; } = true;
|
||||
|
||||
#endregion
|
||||
|
||||
internal static LegacyServerSettings? FromFile(string path)
|
||||
{
|
||||
string data = File.ReadAllText(path);
|
||||
return JsonSerializer.Deserialize<LegacyServerSettings>(data);
|
||||
}
|
||||
|
||||
internal ServerConfiguration ToNewConfiguration()
|
||||
{
|
||||
ServerConfiguration configuration = new();
|
||||
configuration.ConfigReloading = this.ConfigReloading;
|
||||
configuration.AnnounceText = this.AnnounceText;
|
||||
configuration.EulaText = this.EulaText;
|
||||
configuration.ExternalUrl = this.ExternalUrl;
|
||||
configuration.DbConnectionString = this.DbConnectionString;
|
||||
configuration.CheckForUnsafeFiles = this.CheckForUnsafeFiles;
|
||||
configuration.UserInputFilterMode = this.UserInputFilterMode;
|
||||
|
||||
// configuration categories
|
||||
configuration.InfluxDB = new InfluxDBConfiguration
|
||||
{
|
||||
InfluxEnabled = this.InfluxEnabled,
|
||||
LoggingEnabled = this.InfluxLoggingEnabled,
|
||||
Bucket = this.InfluxBucket,
|
||||
Organization = this.InfluxOrg,
|
||||
Token = this.InfluxToken,
|
||||
Url = InfluxUrl,
|
||||
};
|
||||
|
||||
configuration.Authentication = new AuthenticationConfiguration
|
||||
{
|
||||
RegistrationEnabled = this.RegistrationEnabled,
|
||||
BlockDeniedUsers = this.BlockDeniedUsers,
|
||||
UseExternalAuth = this.UseExternalAuth,
|
||||
};
|
||||
|
||||
configuration.Captcha = new CaptchaConfiguration
|
||||
{
|
||||
CaptchaEnabled = this.HCaptchaEnabled,
|
||||
SiteKey = this.HCaptchaSiteKey,
|
||||
Secret = this.HCaptchaSecret,
|
||||
};
|
||||
|
||||
configuration.Mail = new MailConfiguration
|
||||
{
|
||||
MailEnabled = this.SMTPEnabled,
|
||||
Host = this.SMTPHost,
|
||||
Password = this.SMTPPassword,
|
||||
Port = this.SMTPPort,
|
||||
FromAddress = this.SMTPFromAddress,
|
||||
FromName = this.SMTPFromName,
|
||||
UseSSL = this.SMTPSsl,
|
||||
};
|
||||
|
||||
configuration.DigestKey = new DigestKeyConfiguration
|
||||
{
|
||||
PrimaryDigestKey = this.ServerDigestKey,
|
||||
AlternateDigestKey = this.AlternateDigestKey,
|
||||
};
|
||||
|
||||
configuration.DiscordIntegration = new DiscordIntegrationConfiguration
|
||||
{
|
||||
DiscordIntegrationEnabled = this.DiscordWebhookEnabled,
|
||||
Url = this.DiscordWebhookUrl,
|
||||
};
|
||||
|
||||
configuration.GoogleAnalytics = new GoogleAnalyticsConfiguration
|
||||
{
|
||||
AnalyticsEnabled = this.GoogleAnalyticsEnabled,
|
||||
Id = this.GoogleAnalyticsId,
|
||||
};
|
||||
|
||||
configuration.UserGeneratedContentLimits = new UserGeneratedContentLimitConfiguration
|
||||
{
|
||||
BooingEnabled = this.BooingEnabled,
|
||||
EntitledSlots = this.EntitledSlots,
|
||||
ListsQuota = this.ListsQuota,
|
||||
PhotosQuota = this.PhotosQuota,
|
||||
LevelCommentsEnabled = this.LevelCommentsEnabled,
|
||||
LevelReviewsEnabled = this.LevelReviewsEnabled,
|
||||
ProfileCommentsEnabled = this.ProfileCommentsEnabled,
|
||||
};
|
||||
|
||||
configuration.WebsiteConfiguration = new WebsiteConfiguration
|
||||
{
|
||||
MissingIconHash = this.MissingIconHash,
|
||||
ConvertAssetsOnStartup = this.ConvertAssetsOnStartup,
|
||||
};
|
||||
|
||||
return configuration;
|
||||
}
|
||||
}
|
189
ProjectLighthouse/Types/Settings/ServerConfiguration.cs
Normal file
189
ProjectLighthouse/Types/Settings/ServerConfiguration.cs
Normal file
|
@ -0,0 +1,189 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings.ConfigurationCategories;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings.Legacy;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
|
||||
[Serializable]
|
||||
public class ServerConfiguration
|
||||
{
|
||||
// HEY, YOU!
|
||||
// THIS VALUE MUST BE INCREMENTED FOR EVERY CONFIG CHANGE!
|
||||
//
|
||||
// This is so Lighthouse can properly identify outdated configurations and update them with newer settings accordingly.
|
||||
// If you are modifying anything here that isn't outside of a method, this value MUST be incremented.
|
||||
// It is also strongly recommended to not remove any items, else it will cause deserialization errors.
|
||||
// You can use an ObsoleteAttribute instead. Make sure you set it to error, though.
|
||||
//
|
||||
// Thanks for listening~
|
||||
public const int CurrentConfigVersion = 1;
|
||||
|
||||
#region Meta
|
||||
|
||||
public static ServerConfiguration Instance;
|
||||
|
||||
[YamlMember(Alias = "configVersionDoNotModifyOrYouWillBeSlapped")]
|
||||
public int ConfigVersion { get; set; } = CurrentConfigVersion;
|
||||
|
||||
public const string ConfigFileName = "lighthouse.yml";
|
||||
public const string LegacyConfigFileName = LegacyServerSettings.ConfigFileName;
|
||||
|
||||
#endregion Meta
|
||||
|
||||
#region Setup
|
||||
|
||||
private static FileSystemWatcher fileWatcher;
|
||||
|
||||
// ReSharper disable once NotNullMemberIsNotInitialized
|
||||
#pragma warning disable CS8618
|
||||
static ServerConfiguration()
|
||||
{
|
||||
if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own
|
||||
|
||||
Logger.LogInfo("Loading config...", LogArea.Config);
|
||||
|
||||
ServerConfiguration? tempConfig;
|
||||
|
||||
// If a valid YML configuration is available!
|
||||
if (File.Exists(ConfigFileName) && (tempConfig = fromFile(ConfigFileName)) != null)
|
||||
{
|
||||
// Instance = JsonSerializer.Deserialize<ServerConfiguration>(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName));
|
||||
Instance = tempConfig;
|
||||
|
||||
if (Instance.ConfigVersion < CurrentConfigVersion)
|
||||
{
|
||||
Logger.LogInfo($"Upgrading config file from version {Instance.ConfigVersion} to version {CurrentConfigVersion}", LogArea.Config);
|
||||
Instance.ConfigVersion = CurrentConfigVersion;
|
||||
|
||||
Instance.writeConfig(ConfigFileName);
|
||||
}
|
||||
}
|
||||
// If we have a valid legacy configuration we can migrate, let's do it now.
|
||||
else if (File.Exists(LegacyConfigFileName))
|
||||
{
|
||||
Logger.LogWarn("This version of Project Lighthouse now uses YML instead of JSON to store configuration.", LogArea.Config);
|
||||
Logger.LogWarn
|
||||
("As such, the config will now be migrated to use YML. Do not modify the original JSON file; changes will not be kept.", LogArea.Config);
|
||||
Logger.LogInfo($"The new configuration is stored at {ConfigFileName}.", LogArea.Config);
|
||||
|
||||
LegacyServerSettings? legacyConfig = LegacyServerSettings.FromFile(LegacyConfigFileName);
|
||||
Debug.Assert(legacyConfig != null);
|
||||
Instance = legacyConfig.ToNewConfiguration();
|
||||
|
||||
Instance.writeConfig(ConfigFileName);
|
||||
|
||||
Logger.LogSuccess("The configuration migration completed successfully.", LogArea.Config);
|
||||
}
|
||||
// If there is no valid YML configuration available,
|
||||
// generate a blank one and ask the server operator to configure it, then exit.
|
||||
else
|
||||
{
|
||||
new ServerConfiguration().writeConfig(ConfigFileName + ".configme");
|
||||
|
||||
Logger.LogWarn
|
||||
(
|
||||
"The configuration file was not found. " +
|
||||
"A blank configuration file has been created for you at " +
|
||||
$"{Path.Combine(Environment.CurrentDirectory, ConfigFileName + ".configme")}",
|
||||
LogArea.Config
|
||||
);
|
||||
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
// Set up reloading
|
||||
if (Instance.ConfigReloading)
|
||||
{
|
||||
Logger.LogInfo("Setting up config reloading...", LogArea.Config);
|
||||
fileWatcher = new FileSystemWatcher
|
||||
{
|
||||
Path = Environment.CurrentDirectory,
|
||||
Filter = ConfigFileName,
|
||||
NotifyFilter = NotifyFilters.LastWrite, // only watch for writes to config file
|
||||
};
|
||||
|
||||
fileWatcher.Changed += onConfigChanged; // add event handler
|
||||
|
||||
fileWatcher.EnableRaisingEvents = true; // begin watching
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS8618
|
||||
|
||||
private static void onConfigChanged(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
Debug.Assert(e.Name == ConfigFileName);
|
||||
Logger.LogInfo("Configuration file modified, reloading config...", LogArea.Config);
|
||||
Logger.LogWarn("Some changes may not apply; they will require a restart of Lighthouse.", LogArea.Config);
|
||||
|
||||
ServerConfiguration? configuration = fromFile(ConfigFileName);
|
||||
if (configuration == null)
|
||||
{
|
||||
Logger.LogWarn("The new configuration was unable to be loaded for some reason. The old config has been kept.", LogArea.Config);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = configuration;
|
||||
|
||||
Logger.LogSuccess("Successfully reloaded the configuration!", LogArea.Config);
|
||||
}
|
||||
|
||||
private static INamingConvention namingConvention = CamelCaseNamingConvention.Instance;
|
||||
|
||||
private static ServerConfiguration? fromFile(string path)
|
||||
{
|
||||
IDeserializer deserializer = new DeserializerBuilder().WithNamingConvention(namingConvention).Build();
|
||||
|
||||
string text;
|
||||
|
||||
try
|
||||
{
|
||||
text = File.ReadAllText(path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return deserializer.Deserialize<ServerConfiguration>(text);
|
||||
}
|
||||
|
||||
private void writeConfig(string path)
|
||||
{
|
||||
ISerializer serializer = new SerializerBuilder().WithNamingConvention(namingConvention).Build();
|
||||
|
||||
File.WriteAllText(path, serializer.Serialize(this));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public string ListenUrl { get; set; } = "http://localhost:10060";
|
||||
public string DbConnectionString { get; set; } = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse";
|
||||
public string ExternalUrl { get; set; } = "http://localhost:10060";
|
||||
public bool ConfigReloading { get; set; }
|
||||
public string EulaText { get; set; } = "";
|
||||
#if !DEBUG
|
||||
public string AnnounceText { get; set; } = "You are now logged in as %user.";
|
||||
#else
|
||||
public string AnnounceText { get; set; } = "You are now logged in as %user (id: %id).";
|
||||
#endif
|
||||
public bool CheckForUnsafeFiles { get; set; } = true;
|
||||
|
||||
public FilterMode UserInputFilterMode { get; set; } = FilterMode.None;
|
||||
|
||||
public AuthenticationConfiguration Authentication { get; set; } = new();
|
||||
public CaptchaConfiguration Captcha { get; set; } = new();
|
||||
public DigestKeyConfiguration DigestKey { get; set; } = new();
|
||||
public DiscordIntegrationConfiguration DiscordIntegration { get; set; } = new();
|
||||
public GoogleAnalyticsConfiguration GoogleAnalytics { get; set; } = new();
|
||||
public InfluxDBConfiguration InfluxDB { get; set; } = new();
|
||||
public MailConfiguration Mail { get; set; } = new();
|
||||
public UserGeneratedContentLimitConfiguration UserGeneratedContentLimits { get; set; } = new();
|
||||
public WebsiteConfiguration WebsiteConfiguration { get; set; } = new();
|
||||
|
||||
}
|
|
@ -1,198 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
|
||||
[Serializable]
|
||||
public class ServerSettings
|
||||
{
|
||||
public const int CurrentConfigVersion = 26; // MUST BE INCREMENTED FOR EVERY CONFIG CHANGE!
|
||||
private static FileSystemWatcher fileWatcher;
|
||||
|
||||
// ReSharper disable once NotNullMemberIsNotInitialized
|
||||
static ServerSettings()
|
||||
{
|
||||
if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own
|
||||
|
||||
Logger.LogInfo("Loading config...", LogArea.Config);
|
||||
|
||||
if (File.Exists(ConfigFileName))
|
||||
{
|
||||
string configFile = File.ReadAllText(ConfigFileName);
|
||||
|
||||
Instance = JsonSerializer.Deserialize<ServerSettings>(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName));
|
||||
|
||||
if (Instance.ConfigVersion < CurrentConfigVersion)
|
||||
{
|
||||
Logger.LogInfo($"Upgrading config file from version {Instance.ConfigVersion} to version {CurrentConfigVersion}", LogArea.Config);
|
||||
Instance.ConfigVersion = CurrentConfigVersion;
|
||||
configFile = JsonSerializer.Serialize
|
||||
(
|
||||
Instance,
|
||||
typeof(ServerSettings),
|
||||
new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
}
|
||||
);
|
||||
|
||||
File.WriteAllText(ConfigFileName, configFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string configFile = JsonSerializer.Serialize
|
||||
(
|
||||
new ServerSettings(),
|
||||
typeof(ServerSettings),
|
||||
new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
}
|
||||
);
|
||||
|
||||
File.WriteAllText(ConfigFileName, configFile);
|
||||
|
||||
Logger.LogWarn
|
||||
(
|
||||
"The configuration file was not found. " +
|
||||
"A blank configuration file has been created for you at " +
|
||||
$"{Path.Combine(Environment.CurrentDirectory, ConfigFileName)}",
|
||||
LogArea.Config
|
||||
);
|
||||
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
// Set up reloading
|
||||
if (Instance.ConfigReloading)
|
||||
{
|
||||
Logger.LogInfo("Setting up config reloading...", LogArea.Config);
|
||||
fileWatcher = new FileSystemWatcher
|
||||
{
|
||||
Path = Environment.CurrentDirectory,
|
||||
Filter = ConfigFileName,
|
||||
NotifyFilter = NotifyFilters.LastWrite, // only watch for writes to config file
|
||||
};
|
||||
|
||||
fileWatcher.Changed += onConfigChanged; // add event handler
|
||||
|
||||
fileWatcher.EnableRaisingEvents = true; // begin watching
|
||||
}
|
||||
}
|
||||
|
||||
private static void onConfigChanged(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
Debug.Assert(e.Name == ConfigFileName);
|
||||
Logger.LogInfo("Configuration file modified, reloading config.", LogArea.Config);
|
||||
Logger.LogWarn("Some changes may not apply, in which case may require a restart of Project Lighthouse.", LogArea.Config);
|
||||
|
||||
string configFile = File.ReadAllText(ConfigFileName);
|
||||
Instance = JsonSerializer.Deserialize<ServerSettings>(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName));
|
||||
}
|
||||
|
||||
public bool InfluxEnabled { get; set; }
|
||||
public bool InfluxLoggingEnabled { get; set; }
|
||||
public string InfluxOrg { get; set; } = "lighthouse";
|
||||
public string InfluxBucket { get; set; } = "lighthouse";
|
||||
public string InfluxToken { get; set; } = "";
|
||||
public string InfluxUrl { get; set; } = "http://localhost:8086";
|
||||
|
||||
public string EulaText { get; set; } = "";
|
||||
|
||||
#if !DEBUG
|
||||
public string AnnounceText { get; set; } = "You are now logged in as %user.";
|
||||
#else
|
||||
public string AnnounceText { get; set; } = "You are now logged in as %user (id: %id).";
|
||||
#endif
|
||||
|
||||
public string DbConnectionString { get; set; } = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse";
|
||||
|
||||
public string ExternalUrl { get; set; } = "http://localhost:10060";
|
||||
public string ServerDigestKey { get; set; } = "";
|
||||
public string AlternateDigestKey { get; set; } = "";
|
||||
public bool UseExternalAuth { get; set; }
|
||||
|
||||
public bool CheckForUnsafeFiles { get; set; } = true;
|
||||
|
||||
public bool RegistrationEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount of slots allowed on users' earth
|
||||
/// </summary>
|
||||
public int EntitledSlots { get; set; } = 50;
|
||||
|
||||
public int ListsQuota { get; set; } = 50;
|
||||
|
||||
public int PhotosQuota { get; set; } = 500;
|
||||
|
||||
public bool ProfileCommentsEnabled { get; set; } = true;
|
||||
|
||||
public bool LevelCommentsEnabled { get; set; } = true;
|
||||
|
||||
public bool LevelReviewsEnabled { get; set; } = true;
|
||||
|
||||
public bool GoogleAnalyticsEnabled { get; set; }
|
||||
|
||||
public string GoogleAnalyticsId { get; set; } = "";
|
||||
|
||||
public bool BlockDeniedUsers { get; set; } = true;
|
||||
|
||||
public bool BooingEnabled { get; set; } = true;
|
||||
|
||||
public FilterMode UserInputFilterMode { get; set; } = FilterMode.None;
|
||||
|
||||
public bool DiscordWebhookEnabled { get; set; }
|
||||
|
||||
public string DiscordWebhookUrl { get; set; } = "";
|
||||
|
||||
public bool ConfigReloading { get; set; } = true;
|
||||
|
||||
public string MissingIconHash { get; set; } = "";
|
||||
|
||||
public bool HCaptchaEnabled { get; set; }
|
||||
|
||||
public string HCaptchaSiteKey { get; set; } = "";
|
||||
|
||||
public string HCaptchaSecret { get; set; } = "";
|
||||
|
||||
public string ServerListenUrl { get; set; } = "http://localhost:10060";
|
||||
|
||||
public bool ConvertAssetsOnStartup { get; set; } = true;
|
||||
|
||||
#region SMTP
|
||||
|
||||
public bool SMTPEnabled { get; set; }
|
||||
|
||||
public string SMTPHost { get; set; } = "";
|
||||
|
||||
public int SMTPPort { get; set; } = 587;
|
||||
|
||||
public string SMTPFromAddress { get; set; } = "lighthouse@example.com";
|
||||
|
||||
public string SMTPFromName { get; set; } = "Project Lighthouse";
|
||||
|
||||
public string SMTPPassword { get; set; } = "";
|
||||
|
||||
public bool SMTPSsl { get; set; } = true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Meta
|
||||
|
||||
[NotNull]
|
||||
public static ServerSettings Instance;
|
||||
|
||||
[JsonPropertyName("ConfigVersionDoNotModifyOrYouWillBeSlapped")]
|
||||
public int ConfigVersion { get; set; } = CurrentConfigVersion;
|
||||
|
||||
public const string ConfigFileName = "lighthouse.config.json";
|
||||
|
||||
#endregion Meta
|
||||
|
||||
}
|
|
@ -64,7 +64,7 @@ public class User
|
|||
if (string.IsNullOrWhiteSpace(avatarHash) || this.IconHash.StartsWith('g')) avatarHash = this.YayHash;
|
||||
if (string.IsNullOrWhiteSpace(avatarHash)) avatarHash = this.MehHash;
|
||||
if (string.IsNullOrWhiteSpace(avatarHash)) avatarHash = this.BooHash;
|
||||
if (string.IsNullOrWhiteSpace(avatarHash)) avatarHash = ServerSettings.Instance.MissingIconHash;
|
||||
if (string.IsNullOrWhiteSpace(avatarHash)) avatarHash = ServerConfiguration.Instance.WebsiteConfiguration.MissingIconHash;
|
||||
|
||||
return avatarHash;
|
||||
}
|
||||
|
@ -149,13 +149,17 @@ public class User
|
|||
LbpSerializer.StringElement("game", (int)gameVersion) +
|
||||
this.serializeSlots(gameVersion) +
|
||||
LbpSerializer.StringElement("lists", this.Lists) +
|
||||
LbpSerializer.StringElement("lists_quota", ServerSettings.Instance.ListsQuota) + // technically not a part of the user but LBP expects it
|
||||
LbpSerializer.StringElement
|
||||
(
|
||||
"lists_quota",
|
||||
ServerConfiguration.Instance.UserGeneratedContentLimits.ListsQuota
|
||||
) + // technically not a part of the user but LBP expects it
|
||||
LbpSerializer.StringElement("biography", this.Biography) +
|
||||
LbpSerializer.StringElement("reviewCount", this.Reviews) +
|
||||
LbpSerializer.StringElement("commentCount", this.Comments) +
|
||||
LbpSerializer.StringElement("photosByMeCount", this.PhotosByMe) +
|
||||
LbpSerializer.StringElement("photosWithMeCount", this.PhotosWithMe) +
|
||||
LbpSerializer.StringElement("commentsEnabled", ServerSettings.Instance.ProfileCommentsEnabled) +
|
||||
LbpSerializer.StringElement("commentsEnabled", ServerConfiguration.Instance.UserGeneratedContentLimits.ProfileCommentsEnabled) +
|
||||
LbpSerializer.StringElement("location", this.Location.Serialize()) +
|
||||
LbpSerializer.StringElement("favouriteSlotCount", this.HeartedLevels) +
|
||||
LbpSerializer.StringElement("favouriteUserCount", this.HeartedUsers) +
|
||||
|
@ -204,7 +208,7 @@ public class User
|
|||
|
||||
[JsonIgnore]
|
||||
[XmlIgnore]
|
||||
public int EntitledSlots => ServerSettings.Instance.EntitledSlots + this.AdminGrantedSlots;
|
||||
public int EntitledSlots => ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots + this.AdminGrantedSlots;
|
||||
|
||||
/// <summary>
|
||||
/// The number of slots remaining on the earth
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue