Skip to content

Instantly share code, notes, and snippets.

@EdCharbeneau
Forked from Eilon/DevHttpsConnectionHelper.cs
Last active March 15, 2023 00:42
Show Gist options
  • Save EdCharbeneau/ed3d44d8298319c201f276de7a0580f1 to your computer and use it in GitHub Desktop.
Save EdCharbeneau/ed3d44d8298319c201f276de7a0580f1 to your computer and use it in GitHub Desktop.
Dev helper for bypassing SSL connections to localhost on Android
// forked from https://gist.github.com/Eilon/49e3c5216abfa3eba81e453d45cba2d4
// by https://gist.github.com/Eilon
// modified by https://gist.github.com/EdCharbeneau
using System.Net.Security;
public class DevHttpsConnectionHelper
{
public DevHttpsConnectionHelper(int sslPort)
{
DevServerRootUrl = new UriBuilder("https", DevServerName, sslPort).Uri.ToString();
#if WINDOWS
LazyHttpClient = new Lazy<HttpClient>(() => new HttpClient());
#else
LazyHttpClient = new Lazy<HttpClient>(() => new HttpClient(GetPlatformMessageHandler()));
#endif
}
public string DevServerName =>
#if WINDOWS
"localhost";
#elif ANDROID
"10.0.2.2";
#else
throw new PlatformNotSupportedException("Only Windows and Android currently supported.");
#endif
public string DevServerRootUrl { get; }
private Lazy<HttpClient> LazyHttpClient;
public HttpClient HttpClient => LazyHttpClient.Value;
public HttpMessageHandler GetPlatformMessageHandler()
{
#if ANDROID
var handler = new CustomAndroidMessageHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
{
if (cert != null && cert.Issuer.Equals("CN=localhost"))
return true;
return errors == SslPolicyErrors.None;
};
return handler;
#else
throw new PlatformNotSupportedException("Only Windows and Android currently supported.");
#endif
}
#if ANDROID
internal sealed class CustomAndroidMessageHandler : Xamarin.Android.Net.AndroidMessageHandler
{
protected override Javax.Net.Ssl.IHostnameVerifier GetSSLHostnameVerifier(Javax.Net.Ssl.HttpsURLConnection connection)
=> new CustomHostnameVerifier();
private sealed class CustomHostnameVerifier : Java.Lang.Object, Javax.Net.Ssl.IHostnameVerifier
{
public bool Verify(string hostname, Javax.Net.Ssl.ISSLSession session)
{
return
Javax.Net.Ssl.HttpsURLConnection.DefaultHostnameVerifier.Verify(hostname, session)
|| hostname == "10.0.2.2" && session.PeerPrincipal?.Name == "CN=localhost";
}
}
}
#endif
}
// by https://gist.github.com/EdCharbeneau
public static class DevHttpsConnectionHelperExtensions
{
/// <summary>
/// Configures HttpClient to use localhost or 10.0.2.2 and bypass certificate checking on Android.
/// </summary>
/// <param name="sslPort">Development server port</param>
/// <returns>The IServiceCollection</returns>
public static IServiceCollection AddDevHttpClient(this IServiceCollection services, int sslPort)
{
var devSslHelper = new DevHttpsConnectionHelper(sslPort);
var http = devSslHelper.HttpClient;
http.BaseAddress = new Uri(devSslHelper.DevServerRootUrl);
services.AddScoped(sp => http);
return services;
}
}
#if DEBUG
builder.Services.AddDevHttpClient(7030);
#else
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("Server Address") });
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment