Skip to content
Open
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
28 changes: 17 additions & 11 deletions ASFFreeGames/HttpClientSimple/SimpleHttpClientFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using ArchiSteamFarm.Storage;
using ASFFreeGames.Configurations;
Expand All @@ -21,7 +20,7 @@ public sealed class SimpleHttpClientFactory(ASFFreeGamesOptions options) : IDisp
"no-proxy"
};

private readonly Dictionary<ECacheKey, Tuple<WebProxy?, SimpleHttpClient>> Cache = new();
private readonly Dictionary<ECacheKey, Tuple<IWebProxy?, SimpleHttpClient>> Cache = new();

private enum ECacheKey {
Generic,
Expand All @@ -35,38 +34,45 @@ private SimpleHttpClient CreateFor(ECacheKey key, string? proxy = null) {
proxy = options.Proxy;
}

WebProxy? webProxy;
IWebProxy? webProxy;

if (DisableProxyStrings.Contains(proxy ?? "")) {
webProxy = null;
}
else if (!string.IsNullOrWhiteSpace(proxy)) {
webProxy = new WebProxy(proxy, BypassOnLocal: true);
SimpleWebProxy simpleProxy = new(proxy, bypassOnLocal: true);

if (Uri.TryCreate(proxy, UriKind.Absolute, out Uri? uri) && !string.IsNullOrWhiteSpace(uri.UserInfo)) {
string[] split = uri.UserInfo.Split(':');

if (split.Length == 2) {
webProxy.Credentials = new NetworkCredential(split[0], split[1]);
simpleProxy.Credentials = new NetworkCredential(split[0], split[1]);
}
Comment on lines 46 to 50

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current method of splitting uri.UserInfo to parse credentials can fail if the password contains a colon. Using Split(':') will result in more than two parts, causing the if (split.Length == 2) check to fail and preventing credentials from being set. To make this more robust, you should split on the first colon only.

                                string[] split = uri.UserInfo.Split(new[] { ':' }, 2);

				if (split.Length == 2) {
					simpleProxy.Credentials = new NetworkCredential(split[0], split[1]);
				}

}

webProxy = simpleProxy;
}
else {
webProxy = ArchiSteamFarm.Core.ASF.GlobalConfig?.WebProxy;
}

lock (Cache) {
if (Cache.TryGetValue(key, out Tuple<WebProxy?, SimpleHttpClient>? cached)) {
if (cached.Item1?.Address == webProxy?.Address) {
if (Cache.TryGetValue(key, out Tuple<IWebProxy?, SimpleHttpClient>? cached)) {
// Use a test URI to get proxy addresses via IWebProxy interface
// This avoids direct WebProxy type references which cause runtime issues
Uri testUri = new("http://test.example.com", UriKind.Absolute);
Uri? cachedAddress = cached.Item1?.GetProxy(testUri);
Uri? currentAddress = webProxy?.GetProxy(testUri);

if (cachedAddress == currentAddress) {
return cached.Item2;
}
else {
Cache.Remove(key);
}

Cache.Remove(key);
}

#pragma warning disable CA2000
Tuple<WebProxy?, SimpleHttpClient> tuple = new(webProxy, new SimpleHttpClient(webProxy));
Tuple<IWebProxy?, SimpleHttpClient> tuple = new(webProxy, new SimpleHttpClient(webProxy));
#pragma warning restore CA2000
Cache.Add(key, tuple);

Expand Down
24 changes: 24 additions & 0 deletions ASFFreeGames/HttpClientSimple/SimpleWebProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Net;

namespace Maxisoft.ASF.HttpClientSimple;

/// <summary>
/// A simple IWebProxy implementation that avoids using System.Net.WebProxy
/// to prevent runtime version mismatch issues with WebProxy constructors.
/// </summary>
public sealed class SimpleWebProxy : IWebProxy {
public Uri ProxyAddress { get; }
public bool BypassOnLocal { get; }
public ICredentials? Credentials { get; set; }

public SimpleWebProxy(string address, bool bypassOnLocal = true) {
ProxyAddress = new Uri(address);
BypassOnLocal = bypassOnLocal;
}

public Uri? GetProxy(Uri destination) => ProxyAddress;

public bool IsBypassed(Uri host) =>
BypassOnLocal && (host.IsLoopback || host.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase));
}
8 changes: 5 additions & 3 deletions ASFFreeGames/Utils/LoggerFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public IDisposable DisableLogging(Func<LogEventInfo, bool> filter, [NotNull] Bot
logger.Factory.ReconfigExistingLoggers();
}

return new LoggerRemoveFilterDisposable(node);
return new LoggerRemoveFilterDisposable(filters, node);
}
}

Expand Down Expand Up @@ -126,8 +126,10 @@ private static Logger GetLogger(ArchiLogger logger, string name = "ASF") {
private bool RemoveFilters(BotName botName) => Filters.TryRemove(botName, out _);

// A class that implements a disposable object for removing filters
private sealed class LoggerRemoveFilterDisposable(LinkedListNode<Func<LogEventInfo, bool>> node) : IDisposable {
public void Dispose() => node.List?.Remove(node);
private sealed class LoggerRemoveFilterDisposable(
LinkedList<Func<LogEventInfo, bool>> list,
LinkedListNode<Func<LogEventInfo, bool>> node) : IDisposable {
public void Dispose() => list.Remove(node);
}

// A class that implements a custom filter that invokes a method
Expand Down
5 changes: 5 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
<NoWarn>NU1507</NoWarn>
</PropertyGroup>

<!-- Override ASF's TreatWarningsAsErrors for Release builds to allow nullable warnings in ASF code -->
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>

<!-- Reset ASF signing settings, as we'll use our own logic -->
<PropertyGroup>
<AssemblyOriginatorKeyFile />
Expand Down