Skip to content

Commit

Permalink
Change HTTPS proxy to work off redirects towards an external proxy (#668
Browse files Browse the repository at this point in the history
)

This allows us to use an external proxy, instead of the buggy proxy that
I had originally written. Sadly we cant redirect directly to prod
because of a bug in the original game (after a redirect it still uses
the pre-redirect host header value with the new server).

In practice, the proxy.json config will probably just point to the same
machine as Refresh.HttpsProxy itself, but with a different port, which
is hosting a standard nginx HTTP proxy server.

This PR also fixes the middleware order
  • Loading branch information
jvyden authored Oct 5, 2024
2 parents 97b3b8d + f5d622c commit b5b8a17
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 92 deletions.
36 changes: 36 additions & 0 deletions Refresh.Common/Extensions/NameValueCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Specialized;
using System.Text;
using System.Web;

namespace Refresh.Common.Extensions;

public static class NameValueCollectionExtensions
{
public static string ToQueryString(this NameValueCollection queryParams)
{
StringBuilder builder = new();

if (queryParams.Count == 0)
return string.Empty;

builder.Append('?');
for (int i = 0; i < queryParams.Count; i++)
{
string? key = queryParams.GetKey(i);
string? val = queryParams.Get(i);

if (key == null)
continue;

builder.Append(HttpUtility.UrlEncode(key));
builder.Append('=');
if(val != null)
builder.Append(HttpUtility.UrlEncode(val));

if(i < queryParams.Count - 1)
builder.Append('&');
}

return builder.ToString();
}
}
12 changes: 9 additions & 3 deletions Refresh.GameServer/Middlewares/DigestMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,15 @@ public void HandleRequest(ListenerContext context, Lazy<IDatabaseContext> databa
}

// If the client asks for a particular digest index, use that digest
if (int.TryParse(context.RequestHeaders["Refresh-Ps3-Digest-Index"], out int ps3DigestIndex) &&
int.TryParse(context.RequestHeaders["Refresh-Ps4-Digest-Index"], out int ps4DigestIndex))
if (int.TryParse(context.Query["force_ps3_digest"], out int ps3DigestIndex) &&
int.TryParse(context.Query["force_ps4_digest"], out int ps4DigestIndex))
{
if (ps3DigestIndex >= this._config.Sha1DigestKeys.Length)
ps3DigestIndex = 0;

if (ps4DigestIndex >= this._config.HmacDigestKeys.Length)
ps4DigestIndex = 0;

string digest = isPs4
? this._config.HmacDigestKeys[ps4DigestIndex]
: this._config.Sha1DigestKeys[ps3DigestIndex];
Expand All @@ -128,7 +134,7 @@ public void HandleRequest(ListenerContext context, Lazy<IDatabaseContext> databa

if(token != null)
gameDatabase.SetTokenDigestInfo(token, digest, isPs4);

return;
}

Expand Down
2 changes: 1 addition & 1 deletion Refresh.GameServer/RefreshGameServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ protected override void SetupMiddlewares()
{
this.Server.AddMiddleware<WebsiteMiddleware>();
this.Server.AddMiddleware(new DeflateMiddleware(this._config!));
this.Server.AddMiddleware<LegacyAdapterMiddleware>();
// Digest middleware must be run before LegacyAdapterMiddleware, because digest is based on the raw route, not the fixed route
this.Server.AddMiddleware(new DigestMiddleware(this._config!));
this.Server.AddMiddleware<CrossOriginMiddleware>();
this.Server.AddMiddleware<PspVersionMiddleware>();
this.Server.AddMiddleware<LegacyAdapterMiddleware>();
this.Server.AddMiddleware(new PresenceAuthenticationMiddleware(this._integrationConfig!));
}

Expand Down
83 changes: 0 additions & 83 deletions Refresh.HttpsProxy/Middlewares/ProxyMiddleware.cs

This file was deleted.

27 changes: 27 additions & 0 deletions Refresh.HttpsProxy/Middlewares/RedirectMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Net;
using Bunkum.Core.Database;
using Bunkum.Core.Endpoints.Middlewares;
using Bunkum.Listener.Request;
using Refresh.Common.Extensions;
using Refresh.HttpsProxy.Config;

namespace Refresh.HttpsProxy.Middlewares;

public class RedirectMiddleware(ProxyConfig config) : IMiddleware
{
public void HandleRequest(ListenerContext context, Lazy<IDatabaseContext> database, Action next)
{
UriBuilder uri = new(config.TargetServerUrl)
{
Path = context.Uri.AbsolutePath,
};

context.Query["force_ps3_digest"] = config.Ps3DigestIndex.ToString();
context.Query["force_ps4_digest"] = config.Ps4DigestIndex.ToString();

uri.Query = context.Query.ToQueryString();

context.ResponseCode = HttpStatusCode.TemporaryRedirect;
context.ResponseHeaders["Location"] = uri.ToString();
}
}
2 changes: 1 addition & 1 deletion Refresh.HttpsProxy/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
Action<BunkumServer> initialize = s =>
{
ProxyConfig config = Config.LoadFromJsonFile<ProxyConfig>("proxy.json", s.Logger);
s.AddMiddleware(new ProxyMiddleware(config));
s.AddMiddleware(new RedirectMiddleware(config));
};

httpsServer.Initialize = initialize;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,13 @@ public void DigestSelectionHeaderWorks(bool isHmac)

string serverDigest = DigestMiddleware.CalculateDigest(digest, endpoint, Encoding.ASCII.GetBytes(expectedResultStr), "", null, false, isHmac);

context.Http.DefaultRequestHeaders.Add("Refresh-Ps3-Digest-Index", "1");
context.Http.DefaultRequestHeaders.Add("Refresh-Ps4-Digest-Index", "1");

// TODO: once we model PS4 clients in our tokens, make the request come from an authenticated PS4 client.
if(isHmac)
context.Http.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "MM CHTTPClient LBP3 01.26");

// send a blank digest to make it have to guess
context.Http.DefaultRequestHeaders.Add("X-Digest-A", "");
HttpResponseMessage response = context.Http.GetAsync(endpoint).Result;
HttpResponseMessage response = context.Http.GetAsync(endpoint + "?force_ps3_digest=1&force_ps4_digest=1").Result;

Assert.Multiple(() =>
{
Expand Down

0 comments on commit b5b8a17

Please sign in to comment.