Skip to content

Commit aeba706

Browse files
authored
Implement checking for the Patchwork user agent (#1090)
* Implement checking for the Patchwork user agent, move logout into standalone method * Quick fixes (awesome name) * 403 user at login instead of logging out at /announce * Move configuration and revert logout changes * Rework parsing to check against GameVersion enum and game token GameVersion * Fix logic error oopsie * Fix Zaprit suggestions * Simplify patchwork game version test * Test patchwork user agent with regex instead * Fix Qodana warnings * Fix remaining Qodana warnings
1 parent df7ebf9 commit aeba706

File tree

7 files changed

+85
-4
lines changed

7 files changed

+85
-4
lines changed

ProjectLighthouse.Servers.GameServer/Controllers/Login/LoginController.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using LBPUnion.ProjectLighthouse.Database;
44
using LBPUnion.ProjectLighthouse.Extensions;
55
using LBPUnion.ProjectLighthouse.Helpers;
6+
using LBPUnion.ProjectLighthouse.Servers.GameServer.Helpers;
67
using LBPUnion.ProjectLighthouse.Logging;
78
using LBPUnion.ProjectLighthouse.Tickets;
89
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
@@ -212,6 +213,14 @@ public async Task<IActionResult> Login()
212213
return this.Forbid();
213214
}
214215

216+
if (ServerConfiguration.Instance.Authentication.RequirePatchworkUserAgent)
217+
{
218+
if (!PatchworkHelper.IsValidPatchworkUserAgent(this.Request.Headers.UserAgent.ToString()))
219+
{
220+
return this.Forbid();
221+
}
222+
}
223+
215224
Logger.Success($"Successfully logged in user {user.Username} as {token.GameVersion} client", LogArea.Login);
216225

217226
user.LastLogin = TimeHelper.TimestampMillis;

ProjectLighthouse.Servers.GameServer/Controllers/Login/LogoutController.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,4 @@ public async Task<IActionResult> OnPost()
3838
return this.Ok();
3939
}
4040

41-
4241
}

ProjectLighthouse.Servers.GameServer/Controllers/MessageController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Text;
1+
using System.Text;
22
using LBPUnion.ProjectLighthouse.Configuration;
33
using LBPUnion.ProjectLighthouse.Database;
44
using LBPUnion.ProjectLighthouse.Extensions;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using LBPUnion.ProjectLighthouse.Configuration;
2+
using System.Text.RegularExpressions;
3+
4+
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Helpers;
5+
6+
public static partial class PatchworkHelper
7+
{
8+
private static readonly int requiredMajor = ServerConfiguration.Instance.Authentication.PatchworkMajorVersionMinimum;
9+
private static readonly int requiredMinor = ServerConfiguration.Instance.Authentication.PatchworkMinorVersionMinimum;
10+
11+
[GeneratedRegex(@"^PatchworkLBP[123V] (\d{1,5})\.(\d{1,5})$")]
12+
private static partial Regex PatchworkUserAgentRegex();
13+
14+
public static bool IsValidPatchworkUserAgent(string userAgent)
15+
{
16+
Match result = PatchworkUserAgentRegex().Match(userAgent);
17+
if (!result.Success) return false;
18+
19+
if (!int.TryParse(result.Groups[1].Value, out int major) || !int.TryParse(result.Groups[2].Value, out int minor))
20+
return false;
21+
22+
return major >= requiredMajor && minor >= requiredMinor;
23+
}
24+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using LBPUnion.ProjectLighthouse.Servers.GameServer.Helpers;
2+
using Xunit;
3+
4+
namespace ProjectLighthouse.Tests.GameApiTests.Unit;
5+
6+
[Trait("Category", "Unit")]
7+
public class PatchworkUserAgentTests
8+
{
9+
[Fact]
10+
public void CanValidatePatchworkUserAgents()
11+
{
12+
string[] validUserAgents = {
13+
"PatchworkLBP1 1.0",
14+
"PatchworkLBP2 2.0",
15+
"PatchworkLBP3 3.0",
16+
"PatchworkLBPV 4.0",
17+
"PatchworkLBP1 1.5",
18+
};
19+
20+
string[] invalidUserAgents = {
21+
// Matching
22+
"patchworklbp1 1.0", // Case sensitive
23+
"ptchwrklbp1 1.0", // Misspelled
24+
"PatchworkLBP1 1", // Missing major/minor
25+
"PatchworkLBP1 1.000001", // Major/minor too long
26+
27+
// Data
28+
"PatchworkLBP1 0.5", // Version number too low
29+
"PatchworkLBP1 A.0" // Int cannot be parsed
30+
};
31+
32+
bool result;
33+
foreach (string userAgent in validUserAgents)
34+
{
35+
result = PatchworkHelper.IsValidPatchworkUserAgent(userAgent);
36+
Assert.True(result, $"Valid user agent: \"{userAgent}\" was evaluated as {result}.");
37+
}
38+
foreach (string userAgent in invalidUserAgents)
39+
{
40+
result = PatchworkHelper.IsValidPatchworkUserAgent(userAgent);
41+
Assert.False(result, $"Invalid user agent: \"{userAgent}\" was evaluated as {result}.");
42+
}
43+
}
44+
}

ProjectLighthouse/Configuration/ConfigurationCategories/AuthenticationConfiguration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,11 @@ public class AuthenticationConfiguration
99
public bool AllowRPCNSignup { get; set; } = true;
1010

1111
public bool AllowPSNSignup { get; set; } = true;
12+
13+
// Require use of Zaprit's "Patchwork" prx plugin's user agent when connecting to the server
14+
// Major and minor version minimums can be left alone if patchwork is not required
15+
public bool RequirePatchworkUserAgent { get; set; } = false;
16+
public int PatchworkMajorVersionMinimum { get; set; } = 1;
17+
public int PatchworkMinorVersionMinimum { get; set; } = 0;
1218

1319
}

ProjectLighthouse/Configuration/ServerConfiguration.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class ServerConfiguration : ConfigurationBase<ServerConfiguration>
1111
// This is so Lighthouse can properly identify outdated configurations and update them with newer settings accordingly.
1212
// If you are modifying anything here, this value MUST be incremented.
1313
// Thanks for listening~
14-
public override int ConfigVersion { get; set; } = 27;
14+
public override int ConfigVersion { get; set; } = 30;
1515

1616
public override string ConfigName { get; set; } = "lighthouse.yml";
1717
public string WebsiteListenUrl { get; set; } = "http://localhost:10060";
@@ -31,7 +31,6 @@ public class ServerConfiguration : ConfigurationBase<ServerConfiguration>
3131
public bool CheckForUnsafeFiles { get; set; } = true;
3232
public bool LogChatFiltering { get; set; } = false;
3333
public bool LogChatMessages { get; set; } = false;
34-
3534
public AuthenticationConfiguration Authentication { get; set; } = new();
3635
public CaptchaConfiguration Captcha { get; set; } = new();
3736
public DigestKeyConfiguration DigestKey { get; set; } = new();

0 commit comments

Comments
 (0)