Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion DevProxy/ApiControllers/ProxyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ namespace DevProxy.ApiControllers;
[ApiController]
[Route("[controller]")]
#pragma warning disable CA1515 // required for the API controller
public sealed class ProxyController(IProxyStateController proxyStateController, IProxyConfiguration proxyConfiguration) : ControllerBase
public sealed class ProxyController(IProxyStateController proxyStateController, IProxyConfiguration proxyConfiguration, ILoggerFactory loggerFactory) : ControllerBase
#pragma warning restore CA1515
{
private readonly IProxyStateController _proxyStateController = proxyStateController;
private readonly IProxyConfiguration _proxyConfiguration = proxyConfiguration;
private readonly ILoggerFactory _loggerFactory = loggerFactory;

[HttpGet]
public ProxyInfo Get() => ProxyInfo.From(_proxyStateController.ProxyState, _proxyConfiguration);
Expand Down Expand Up @@ -114,6 +115,9 @@ public IActionResult GetRootCertificate([FromQuery][Required] string format)
return ValidationProblem(ModelState);
}

// Ensure ProxyServer is initialized with LoggerFactory for Unobtanium logging
ProxyEngine.EnsureProxyServerInitialized(_loggerFactory);

var certificate = ProxyEngine.ProxyServer.CertificateManager.RootCertificate;
if (certificate == null)
{
Expand Down
10 changes: 9 additions & 1 deletion DevProxy/Commands/CertCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ namespace DevProxy.Commands;
sealed class CertCommand : Command
{
private readonly ILogger _logger;
private readonly ILoggerFactory _loggerFactory;
private readonly Option<bool> _forceOption = new("--force", "-f")
{
Description = "Don't prompt for confirmation when removing the certificate"
};

public CertCommand(ILogger<CertCommand> logger) :
public CertCommand(ILogger<CertCommand> logger, ILoggerFactory loggerFactory) :
base("cert", "Manage the Dev Proxy certificate")
{
_logger = logger;
_loggerFactory = loggerFactory;

ConfigureCommand();
}
Expand All @@ -49,6 +51,9 @@ private async Task EnsureCertAsync()

try
{
// Ensure ProxyServer is initialized with LoggerFactory for Unobtanium logging
ProxyEngine.EnsureProxyServerInitialized(_loggerFactory);

_logger.LogInformation("Ensuring certificate exists and is trusted...");
await ProxyEngine.ProxyServer.CertificateManager.EnsureRootCertificateAsync();
_logger.LogInformation("DONE");
Expand Down Expand Up @@ -79,6 +84,9 @@ public void RemoveCert(ParseResult parseResult)

_logger.LogInformation("Uninstalling the root certificate...");

// Ensure ProxyServer is initialized with LoggerFactory for Unobtanium logging
ProxyEngine.EnsureProxyServerInitialized(_loggerFactory);

RemoveTrustedCertificateOnMac();
ProxyEngine.ProxyServer.CertificateManager.RemoveTrustedRootCertificate(machineTrusted: false);

Expand Down
55 changes: 42 additions & 13 deletions DevProxy/Proxy/ProxyEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ sealed class ProxyEngine(
IProxyConfiguration proxyConfiguration,
ISet<UrlToWatch> urlsToWatch,
IProxyStateController proxyController,
ILogger<ProxyEngine> logger) : BackgroundService, IDisposable
ILogger<ProxyEngine> logger,
ILoggerFactory loggerFactory) : BackgroundService, IDisposable
{
private readonly IEnumerable<IPlugin> _plugins = plugins;
private readonly ILogger _logger = logger;
private readonly IProxyConfiguration _config = proxyConfiguration;

internal static ProxyServer ProxyServer { get; private set; }
internal static ProxyServer ProxyServer { get; private set; } = null!;
private static bool _isProxyServerInitialized;
private static readonly object _initLock = new();
private ExplicitProxyEndPoint? _explicitEndPoint;
// lists of URLs to watch, used for intercepting requests
private readonly ISet<UrlToWatch> _urlsToWatch = urlsToWatch;
Expand All @@ -56,23 +59,49 @@ sealed class ProxyEngine(

static ProxyEngine()
{
ProxyServer = new();
ProxyServer.CertificateManager.PfxFilePath = Environment.GetEnvironmentVariable("DEV_PROXY_CERT_PATH") ?? string.Empty;
ProxyServer.CertificateManager.RootCertificateName = "Dev Proxy CA";
ProxyServer.CertificateManager.CertificateStorage = new CertificateDiskCache();
// we need to change this to a value lower than 397
// to avoid the ERR_CERT_VALIDITY_TOO_LONG error in Edge
ProxyServer.CertificateManager.CertificateValidDays = 365;

using var joinableTaskContext = new JoinableTaskContext();
var joinableTaskFactory = new JoinableTaskFactory(joinableTaskContext);
_ = joinableTaskFactory.Run(async () => await ProxyServer.CertificateManager.LoadOrCreateRootCertificateAsync());
// ProxyServer initialization moved to EnsureProxyServerInitialized
// to enable passing ILoggerFactory for Unobtanium logging
}

// Ensure ProxyServer is initialized with the given ILoggerFactory
// This method can be called from multiple places (ProxyEngine, CertCommand, etc.)
internal static void EnsureProxyServerInitialized(ILoggerFactory? loggerFactory = null)
{
if (_isProxyServerInitialized)
{
return;
}

lock (_initLock)
{
if (_isProxyServerInitialized)
{
return;
}

ProxyServer = new(loggerFactory: loggerFactory);
ProxyServer.CertificateManager.PfxFilePath = Environment.GetEnvironmentVariable("DEV_PROXY_CERT_PATH") ?? string.Empty;
ProxyServer.CertificateManager.RootCertificateName = "Dev Proxy CA";
ProxyServer.CertificateManager.CertificateStorage = new CertificateDiskCache();
// we need to change this to a value lower than 397
// to avoid the ERR_CERT_VALIDITY_TOO_LONG error in Edge
ProxyServer.CertificateManager.CertificateValidDays = 365;

using var joinableTaskContext = new JoinableTaskContext();
var joinableTaskFactory = new JoinableTaskFactory(joinableTaskContext);
_ = joinableTaskFactory.Run(async () => await ProxyServer.CertificateManager.LoadOrCreateRootCertificateAsync());

_isProxyServerInitialized = true;
}
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_cancellationToken = stoppingToken;

// Initialize ProxyServer with LoggerFactory for Unobtanium logging
EnsureProxyServerInitialized(loggerFactory);

Debug.Assert(ProxyServer is not null, "Proxy server is not initialized");

if (!_urlsToWatch.Any())
Expand Down