diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ee55c876..5a2142773 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,8 +6,8 @@ env: CONFIGURATION: Release DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: 1 - DOTNET_SDK_VERSION: 3.1 - NET_CORE_VERSION: netcoreapp3.1 + DOTNET_SDK_VERSION: 5.0.100 + NET_CORE_VERSION: net5.0 NET_FRAMEWORK_VERSION: net48 NODE_JS_VERSION: 12 STEAM_TOKEN_DUMPER_NAME: ArchiSteamFarm.OfficialPlugins.SteamTokenDumper diff --git a/.travis.yml b/.travis.yml index 314895d71..354e15e7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ git: depth: 10 # ASF is based on .NET Core platform, we're not building with Mono -dotnet: 3.1 +dotnet: 5.0 mono: none env: @@ -15,7 +15,7 @@ env: - CONFIGURATION: Release - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - DOTNET_NOLOGO: 1 - - NET_CORE_VERSION: netcoreapp3.1 + - NET_CORE_VERSION: net5.0 - STEAM_TOKEN_DUMPER_NAME: ArchiSteamFarm.OfficialPlugins.SteamTokenDumper - VARIANTS="generic linux-arm linux-arm64 linux-x64 osx-x64 win-x64" # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs! addons: @@ -100,6 +100,8 @@ script: set +u # This is needed to continue Travis build matrix: + allow_failures: + - os: osx # We can use fast finish, as we don't need to wait for allow_failures builds to mark build as success fast_finish: true include: @@ -110,5 +112,5 @@ matrix: dist: bionic - os: osx # Ref: https://docs.travis-ci.com/user/reference/osx - dotnet: 3.1.300 # For OSX, we need absolute dotnet version until https://github.com/dotnet/core-setup/issues/4187 is resolved + dotnet: 5.0.100 # For OSX, we need absolute dotnet version until https://github.com/dotnet/core-setup/issues/4187 is resolved osx_image: xcode11.4 diff --git a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj index ce8e5e1d8..775e64a53 100644 --- a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj +++ b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj @@ -7,8 +7,6 @@ all - - diff --git a/ArchiSteamFarm.CustomPlugins.PeriodicGC/ArchiSteamFarm.CustomPlugins.PeriodicGC.csproj b/ArchiSteamFarm.CustomPlugins.PeriodicGC/ArchiSteamFarm.CustomPlugins.PeriodicGC.csproj index c59fa5c3c..775e64a53 100644 --- a/ArchiSteamFarm.CustomPlugins.PeriodicGC/ArchiSteamFarm.CustomPlugins.PeriodicGC.csproj +++ b/ArchiSteamFarm.CustomPlugins.PeriodicGC/ArchiSteamFarm.CustomPlugins.PeriodicGC.csproj @@ -7,7 +7,6 @@ all - diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index fc78cf226..f5599f2ed 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -27,6 +27,7 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using System.Threading; @@ -337,7 +338,7 @@ namespace ArchiSteamFarm { return null; } - if (OS.IsUnix) { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { string executable = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.AssemblyName); if (File.Exists(executable)) { @@ -436,6 +437,10 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(sender) + " || " + nameof(e)); } + if (string.IsNullOrEmpty(e.Name)) { + throw new ArgumentNullException(nameof(e.Name)); + } + await OnChangedFile(e.Name, e.FullPath).ConfigureAwait(false); } @@ -498,6 +503,10 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(sender) + " || " + nameof(e)); } + if (string.IsNullOrEmpty(e.Name)) { + throw new ArgumentNullException(nameof(e.Name)); + } + await OnCreatedFile(e.Name, e.FullPath).ConfigureAwait(false); } @@ -604,6 +613,10 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(sender) + " || " + nameof(e)); } + if (string.IsNullOrEmpty(e.Name)) { + throw new ArgumentNullException(nameof(e.Name)); + } + await OnDeletedFile(e.Name, e.FullPath).ConfigureAwait(false); } @@ -700,6 +713,10 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(sender) + " || " + nameof(e)); } + if (string.IsNullOrEmpty(e.OldName) || string.IsNullOrEmpty(e.Name)) { + throw new ArgumentNullException(nameof(e.OldName) + " || " + nameof(e.Name)); + } + await OnDeletedFile(e.OldName, e.OldFullPath).ConfigureAwait(false); await OnCreatedFile(e.Name, e.FullPath).ConfigureAwait(false); } diff --git a/ArchiSteamFarm/Actions.cs b/ArchiSteamFarm/Actions.cs index 50ae5ca37..f617339ba 100644 --- a/ArchiSteamFarm/Actions.cs +++ b/ArchiSteamFarm/Actions.cs @@ -460,7 +460,7 @@ namespace ArchiSteamFarm { internal void OnDisconnected() => HandledGifts.Clear(); private ulong GetFirstSteamMasterID() { - ulong steamMasterID = Bot.BotConfig.SteamUserPermissions.Where(kv => (kv.Key > 0) && (kv.Key != Bot.SteamID) && new SteamID(kv.Key).IsIndividualAccount && (kv.Value == BotConfig.EPermission.Master)).Select(kv => kv.Key).OrderBy(steamID => steamID).FirstOrDefault(); + ulong steamMasterID = Bot.BotConfig.SteamUserPermissions.Where(kv => (kv.Key > 0) && (kv.Key != Bot.SteamID) && new SteamID(kv.Key).IsIndividualAccount && (kv.Value == BotConfig.EPermission.Master)).Select(kv => kv.Key).OrderBy(steamID => steamID).FirstOrDefault()!; if (steamMasterID > 0) { return steamMasterID; diff --git a/ArchiSteamFarm/ArchiCryptoHelper.cs b/ArchiSteamFarm/ArchiCryptoHelper.cs index 7a3b19656..57cb97a04 100644 --- a/ArchiSteamFarm/ArchiCryptoHelper.cs +++ b/ArchiSteamFarm/ArchiCryptoHelper.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using CryptSharp.Utility; @@ -152,6 +153,10 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(encrypted)); } + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + return null; + } + try { byte[] decryptedData = ProtectedData.Unprotect( Convert.FromBase64String(encrypted), @@ -160,10 +165,6 @@ namespace ArchiSteamFarm { ); return Encoding.UTF8.GetString(decryptedData); - } catch (PlatformNotSupportedException e) { - ASF.ArchiLogger.LogGenericWarningException(e); - - return null; } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); @@ -199,6 +200,10 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(decrypted)); } + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + return null; + } + try { byte[] encryptedData = ProtectedData.Protect( Encoding.UTF8.GetBytes(decrypted), @@ -207,10 +212,6 @@ namespace ArchiSteamFarm { ); return Convert.ToBase64String(encryptedData); - } catch (PlatformNotSupportedException e) { - ASF.ArchiLogger.LogGenericWarningException(e); - - return null; } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); diff --git a/ArchiSteamFarm/ArchiSteamFarm.csproj b/ArchiSteamFarm/ArchiSteamFarm.csproj index c98e8e32d..471561b8d 100644 --- a/ArchiSteamFarm/ArchiSteamFarm.csproj +++ b/ArchiSteamFarm/ArchiSteamFarm.csproj @@ -6,13 +6,6 @@ Exe - - - - - - - @@ -34,8 +27,7 @@ - - + diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index 8abc2b724..0449bc8c6 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -166,7 +166,7 @@ namespace ArchiSteamFarm { Dictionary<(ulong ClassID, ulong InstanceID), Steam.InventoryResponse.Description> descriptions = new Dictionary<(ulong ClassID, ulong InstanceID), Steam.InventoryResponse.Description>(); - foreach (Steam.InventoryResponse.Description description in response.Content.Descriptions.Where(description => description != null)) { + foreach (Steam.InventoryResponse.Description description in response.Content.Descriptions) { if (description.ClassID == 0) { throw new NotSupportedException(string.Format(Strings.ErrorObjectIsNull, nameof(description.ClassID))); } @@ -180,7 +180,7 @@ namespace ArchiSteamFarm { descriptions[key] = description; } - foreach (Steam.Asset asset in response.Content.Assets.Where(asset => asset != null)) { + foreach (Steam.Asset asset in response.Content.Assets) { if (!descriptions.TryGetValue((asset.ClassID, asset.InstanceID), out Steam.InventoryResponse.Description? description) || assetIDs.Contains(asset.AssetID)) { continue; } diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index a91b976ce..db15c2c0b 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -2691,7 +2691,7 @@ namespace ArchiSteamFarm { using SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider(); - sentryHash = sha.ComputeHash(fileStream); + sentryHash = await sha.ComputeHashAsync(fileStream).ConfigureAwait(false); } catch (Exception e) { ArchiLogger.LogGenericException(e); diff --git a/ArchiSteamFarm/BotDatabase.cs b/ArchiSteamFarm/BotDatabase.cs index e0ff63771..956bd31d1 100644 --- a/ArchiSteamFarm/BotDatabase.cs +++ b/ArchiSteamFarm/BotDatabase.cs @@ -124,7 +124,7 @@ namespace ArchiSteamFarm { bool save = false; lock (GamesToRedeemInBackground) { - foreach (DictionaryEntry game in games.Cast().Where(game => !GamesToRedeemInBackground.Contains(game.Key))) { + foreach (DictionaryEntry game in games.OfType().Where(game => !GamesToRedeemInBackground.Contains(game.Key))) { GamesToRedeemInBackground.Add(game.Key, game.Value); save = true; } diff --git a/ArchiSteamFarm/Helpers/CrossProcessFileBasedSemaphore.cs b/ArchiSteamFarm/Helpers/CrossProcessFileBasedSemaphore.cs index e0770e722..581cefbac 100644 --- a/ArchiSteamFarm/Helpers/CrossProcessFileBasedSemaphore.cs +++ b/ArchiSteamFarm/Helpers/CrossProcessFileBasedSemaphore.cs @@ -22,6 +22,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Threading; using System.Threading.Tasks; @@ -161,9 +162,7 @@ namespace ArchiSteamFarm.Helpers { if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath!); - if (OS.IsUnix) { - OS.UnixSetFileAccess(directoryPath!, OS.EUnixPermission.Combined777); - } else { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { DirectoryInfo directoryInfo = new DirectoryInfo(directoryPath!); try { @@ -174,15 +173,15 @@ namespace ArchiSteamFarm.Helpers { // Non-critical, user might have no rights to manage the resource ASF.ArchiLogger.LogGenericDebuggingException(e); } + } else { + OS.UnixSetFileAccess(directoryPath!, OS.EUnixPermission.Combined777); } } try { using (new FileStream(FilePath, FileMode.CreateNew)) { } - if (OS.IsUnix) { - OS.UnixSetFileAccess(FilePath, OS.EUnixPermission.Combined777); - } else { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { FileInfo fileInfo = new FileInfo(FilePath); try { @@ -193,6 +192,8 @@ namespace ArchiSteamFarm.Helpers { // Non-critical, user might have no rights to manage the resource ASF.ArchiLogger.LogGenericDebuggingException(e); } + } else { + OS.UnixSetFileAccess(FilePath, OS.EUnixPermission.Combined777); } } catch (IOException) { // Ignored, if the file was already created in the meantime by another instance, this is fine diff --git a/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs b/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs index a2bd25abb..9b38a3130 100644 --- a/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs +++ b/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs @@ -86,7 +86,11 @@ namespace ArchiSteamFarm.IPC.Integration { return HttpStatusCode.OK; } - IPAddress clientIP = context.Connection.RemoteIpAddress; + IPAddress? clientIP = context.Connection.RemoteIpAddress; + + if (clientIP == null) { + throw new ArgumentNullException(nameof(context.Connection.RemoteIpAddress)); + } if (FailedAuthorizations.TryGetValue(clientIP, out byte attempts)) { if (attempts >= MaxFailedAuthorizationAttempts) { diff --git a/ArchiSteamFarm/OS.cs b/ArchiSteamFarm/OS.cs index e2f557dfc..52f1b76d0 100644 --- a/ArchiSteamFarm/OS.cs +++ b/ArchiSteamFarm/OS.cs @@ -35,15 +35,12 @@ namespace ArchiSteamFarm { // We need to keep this one assigned and not calculated on-demand internal static readonly string ProcessFileName = Process.GetCurrentProcess().MainModule?.FileName ?? throw new ArgumentNullException(nameof(ProcessFileName)); - internal static bool IsUnix => RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX); internal static string Variant => RuntimeInformation.OSDescription.Trim(); - private static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - private static Mutex? SingleInstance; internal static void CoreInit() { - if (IsWindows && !Console.IsOutputRedirected) { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Console.IsOutputRedirected) { // Normally we should use UTF-8 encoding as it's the most correct one for our case, and we already use it on other OSes such as Linux // However, older Windows versions, mainly 7/8.1 can't into UTF-8 without appropriate console font, and expecting from users to change it manually is unwanted // As irrational as it can sound, those versions actually can work with unicode encoding instead, as they magically map it into proper chars despite of incorrect font @@ -74,7 +71,7 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(optimizationMode)); } - if (IsWindows) { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (systemRequired) { WindowsKeepSystemActive(); } @@ -126,7 +123,7 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(path)); } - if (!IsUnix) { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && !RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { return; } @@ -162,7 +159,7 @@ namespace ArchiSteamFarm { } private static void WindowsDisableQuickEditMode() { - if (!IsWindows) { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return; } @@ -182,7 +179,7 @@ namespace ArchiSteamFarm { } private static void WindowsKeepSystemActive() { - if (!IsWindows) { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return; } diff --git a/ArchiSteamFarm/Plugins/PluginsCore.cs b/ArchiSteamFarm/Plugins/PluginsCore.cs index f7c609fb2..2972ab973 100644 --- a/ArchiSteamFarm/Plugins/PluginsCore.cs +++ b/ArchiSteamFarm/Plugins/PluginsCore.cs @@ -56,7 +56,7 @@ namespace ArchiSteamFarm.Plugins { return StringComparer.Ordinal; } - StringComparer? result = results.FirstOrDefault(comparer => comparer != null); + StringComparer? result = results.FirstOrDefault(); return result ?? StringComparer.Ordinal; } @@ -427,7 +427,7 @@ namespace ArchiSteamFarm.Plugins { return null; } - return responses.Where(response => response != null).SelectMany(handler => handler).Where(handler => handler != null).ToHashSet(); + return responses.Where(response => response != null).SelectMany(handlers => handlers ?? Enumerable.Empty()).ToHashSet(); } internal static async Task OnBotTradeOffer(Bot bot, Steam.TradeOffer tradeOffer) { diff --git a/ArchiSteamFarm/RuntimeCompatibility.cs b/ArchiSteamFarm/RuntimeCompatibility.cs index 2922a9e03..7bb480a20 100644 --- a/ArchiSteamFarm/RuntimeCompatibility.cs +++ b/ArchiSteamFarm/RuntimeCompatibility.cs @@ -27,7 +27,9 @@ using JetBrains.Annotations; #if NETFRAMEWORK using Microsoft.AspNetCore.Hosting; using System.Collections.Generic; +using System.IO; using System.Net.WebSockets; +using System.Security.Cryptography; using System.Threading; #endif @@ -135,6 +137,8 @@ namespace ArchiSteamFarm { } #if NETFRAMEWORK + internal static Task ComputeHashAsync(this HashAlgorithm hashAlgorithm, Stream inputStream) => Task.FromResult(hashAlgorithm.ComputeHash(inputStream)); + internal static IWebHostBuilder ConfigureWebHostDefaults(this IWebHostBuilder builder, Action configure) { configure(builder); diff --git a/ArchiSteamFarm/Utilities.cs b/ArchiSteamFarm/Utilities.cs index e1f7041f4..bb1fa5bf2 100644 --- a/ArchiSteamFarm/Utilities.cs +++ b/ArchiSteamFarm/Utilities.cs @@ -217,10 +217,10 @@ namespace ArchiSteamFarm { } [PublicAPI] - public static List SelectElementNodes(this IElement element, string xpath) => element.SelectNodes(xpath).Cast().ToList(); + public static List SelectElementNodes(this IElement element, string xpath) => element.SelectNodes(xpath).OfType().ToList(); [PublicAPI] - public static List SelectNodes(this IDocument document, string xpath) => document.Body.SelectNodes(xpath).Cast().ToList(); + public static List SelectNodes(this IDocument document, string xpath) => document.Body.SelectNodes(xpath).OfType().ToList(); [PublicAPI] public static IElement? SelectSingleElementNode(this IElement element, string xpath) => (IElement?) element.SelectSingleNode(xpath); diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index 1f6a0408e..74913e89a 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -361,32 +361,24 @@ namespace ArchiSteamFarm { continue; } - bool handleError = false; - if (response.StatusCode.IsClientErrorCode()) { if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) { // We're not handling this error, do not try again break; } - handleError = true; - } else if (response.StatusCode.IsServerErrorCode()) { + // We're handling this error, the content isn't available, deal with it + return new StreamResponse(response); + } + + if (response.StatusCode.IsServerErrorCode()) { if (!requestOptions.HasFlag(ERequestOptions.ReturnServerErrors)) { // We're not handling this error, try again continue; } - handleError = true; - } - - if (response.Content == null) { - if (handleError) { - // We're handling this error, the content isn't available, deal with it - return new StreamResponse(response); - } - - // The content isn't available and it's not an error, try again - continue; + // We're handling this error, the content isn't available, deal with it + return new StreamResponse(response); } return new StreamResponse(response, await response.Content.ReadAsStreamAsync().ConfigureAwait(false)); @@ -416,32 +408,24 @@ namespace ArchiSteamFarm { continue; } - bool handleError = false; - if (response.StatusCode.IsClientErrorCode()) { if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) { // We're not handling this error, do not try again break; } - handleError = true; - } else if (response.StatusCode.IsServerErrorCode()) { + // We're handling this error, the content isn't available, deal with it + return new StringResponse(response); + } + + if (response.StatusCode.IsServerErrorCode()) { if (!requestOptions.HasFlag(ERequestOptions.ReturnServerErrors)) { // We're not handling this error, try again continue; } - handleError = true; - } - - if (response.Content == null) { - if (handleError) { - // We're handling this error, the content isn't available, deal with it - return new StringResponse(response); - } - - // The content isn't available and it's not an error, try again - continue; + // We're handling this error, the content isn't available, deal with it + return new StringResponse(response); } return new StringResponse(response, await response.Content.ReadAsStringAsync().ConfigureAwait(false)); @@ -758,32 +742,24 @@ namespace ArchiSteamFarm { continue; } - bool handleError = false; - if (response.StatusCode.IsClientErrorCode()) { if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) { // We're not handling this error, do not try again break; } - handleError = true; - } else if (response.StatusCode.IsServerErrorCode()) { + // We're handling this error, the content isn't available, deal with it + return new StreamResponse(response); + } + + if (response.StatusCode.IsServerErrorCode()) { if (!requestOptions.HasFlag(ERequestOptions.ReturnServerErrors)) { // We're not handling this error, try again continue; } - handleError = true; - } - - if (response.Content == null) { - if (handleError) { - // We're handling this error, the content isn't available, deal with it - return new StreamResponse(response); - } - - // The content isn't available and it's not an error, try again - continue; + // We're handling this error, the content isn't available, deal with it + return new StreamResponse(response); } return new StreamResponse(response, await response.Content.ReadAsStreamAsync().ConfigureAwait(false)); @@ -861,7 +837,7 @@ namespace ArchiSteamFarm { request.Content = content; break; - case IReadOnlyCollection> dictionary: + case IReadOnlyCollection> dictionary: try { request.Content = new FormUrlEncodedContent(dictionary); } catch (UriFormatException) { @@ -920,7 +896,13 @@ namespace ArchiSteamFarm { // WARNING: We still have not disposed response by now, make sure to dispose it ASAP if we're not returning it! if ((response.StatusCode >= HttpStatusCode.Ambiguous) && (response.StatusCode < HttpStatusCode.BadRequest) && (maxRedirections > 0)) { - Uri redirectUri = response.Headers.Location; + Uri? redirectUri = response.Headers.Location; + + if (redirectUri == null) { + ArchiLogger.LogNullError(nameof(redirectUri)); + + return null; + } if (redirectUri.IsAbsoluteUri) { switch (redirectUri.Scheme) { @@ -1002,7 +984,7 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(httpResponseMessage)); } - FinalUri = httpResponseMessage.Headers.Location ?? httpResponseMessage.RequestMessage.RequestUri; + FinalUri = httpResponseMessage.Headers.Location ?? httpResponseMessage.RequestMessage?.RequestUri ?? throw new ArgumentNullException(nameof(FinalUri)); StatusCode = httpResponseMessage.StatusCode; } diff --git a/ArchiSteamFarm/overlay/linux-arm/ArchiSteamFarm-Service.sh b/ArchiSteamFarm/overlay/linux-arm/ArchiSteamFarm-Service.sh index 48c49dcf5..307365d65 100755 --- a/ArchiSteamFarm/overlay/linux-arm/ArchiSteamFarm-Service.sh +++ b/ArchiSteamFarm/overlay/linux-arm/ArchiSteamFarm-Service.sh @@ -62,28 +62,6 @@ CONFIG_PATH="$(pwd)/${CONFIG_PATH}" # Kill underlying ASF process on shell process exit trap "trap - TERM && kill -- -$$" INT TERM -# TODO: Workaround for https://github.com/JustArchiNET/ArchiSteamFarm/issues/1812 -if [ -n "${DOTNET_RUNNING_IN_CONTAINER-}" ] && [ "$DOTNET_RUNNING_IN_CONTAINER" = "true" ]; then - ( - loops=6 # Maximum of 60 seconds for unpack - - while [ "$loops" -gt 0 ]; do - sleep 10 - - if [ -d "/var/tmp/.net" ]; then - find "/var/tmp/.net" -mindepth 2 -name '*\\*' | while IFS="" read -r broken_path; do - fixed_path="$(echo "$broken_path" | sed 's/\\/\//g')" - - mkdir -p "$(dirname "$fixed_path")" - mv "$broken_path" "$fixed_path" - done - fi - - loops="$((loops-1))" - done - ) & -fi - while :; do if [ -f "$CONFIG_PATH" ] && grep -Eq '"Headless":\s+?true' "$CONFIG_PATH"; then # We're running ASF in headless mode so we don't need STDIN diff --git a/ArchiSteamFarm/overlay/linux-arm64/ArchiSteamFarm-Service.sh b/ArchiSteamFarm/overlay/linux-arm64/ArchiSteamFarm-Service.sh index 48c49dcf5..307365d65 100755 --- a/ArchiSteamFarm/overlay/linux-arm64/ArchiSteamFarm-Service.sh +++ b/ArchiSteamFarm/overlay/linux-arm64/ArchiSteamFarm-Service.sh @@ -62,28 +62,6 @@ CONFIG_PATH="$(pwd)/${CONFIG_PATH}" # Kill underlying ASF process on shell process exit trap "trap - TERM && kill -- -$$" INT TERM -# TODO: Workaround for https://github.com/JustArchiNET/ArchiSteamFarm/issues/1812 -if [ -n "${DOTNET_RUNNING_IN_CONTAINER-}" ] && [ "$DOTNET_RUNNING_IN_CONTAINER" = "true" ]; then - ( - loops=6 # Maximum of 60 seconds for unpack - - while [ "$loops" -gt 0 ]; do - sleep 10 - - if [ -d "/var/tmp/.net" ]; then - find "/var/tmp/.net" -mindepth 2 -name '*\\*' | while IFS="" read -r broken_path; do - fixed_path="$(echo "$broken_path" | sed 's/\\/\//g')" - - mkdir -p "$(dirname "$fixed_path")" - mv "$broken_path" "$fixed_path" - done - fi - - loops="$((loops-1))" - done - ) & -fi - while :; do if [ -f "$CONFIG_PATH" ] && grep -Eq '"Headless":\s+?true' "$CONFIG_PATH"; then # We're running ASF in headless mode so we don't need STDIN diff --git a/ArchiSteamFarm/overlay/linux-x64/ArchiSteamFarm-Service.sh b/ArchiSteamFarm/overlay/linux-x64/ArchiSteamFarm-Service.sh index 48c49dcf5..307365d65 100755 --- a/ArchiSteamFarm/overlay/linux-x64/ArchiSteamFarm-Service.sh +++ b/ArchiSteamFarm/overlay/linux-x64/ArchiSteamFarm-Service.sh @@ -62,28 +62,6 @@ CONFIG_PATH="$(pwd)/${CONFIG_PATH}" # Kill underlying ASF process on shell process exit trap "trap - TERM && kill -- -$$" INT TERM -# TODO: Workaround for https://github.com/JustArchiNET/ArchiSteamFarm/issues/1812 -if [ -n "${DOTNET_RUNNING_IN_CONTAINER-}" ] && [ "$DOTNET_RUNNING_IN_CONTAINER" = "true" ]; then - ( - loops=6 # Maximum of 60 seconds for unpack - - while [ "$loops" -gt 0 ]; do - sleep 10 - - if [ -d "/var/tmp/.net" ]; then - find "/var/tmp/.net" -mindepth 2 -name '*\\*' | while IFS="" read -r broken_path; do - fixed_path="$(echo "$broken_path" | sed 's/\\/\//g')" - - mkdir -p "$(dirname "$fixed_path")" - mv "$broken_path" "$fixed_path" - done - fi - - loops="$((loops-1))" - done - ) & -fi - while :; do if [ -f "$CONFIG_PATH" ] && grep -Eq '"Headless":\s+?true' "$CONFIG_PATH"; then # We're running ASF in headless mode so we don't need STDIN diff --git a/Directory.Build.props b/Directory.Build.props index a6dfdc8e1..9d0207523 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 4.3.1.4 + 5.0.0.0 @@ -36,10 +36,10 @@ - netcoreapp3.1;net48 + net5.0;net48 - netcoreapp3.1 + net5.0 diff --git a/Dockerfile b/Dockerfile index f053f11ea..e16572efd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,13 +8,13 @@ RUN echo "node: $(node --version)" && \ npm ci && \ npm run deploy -FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-dotnet +FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-dotnet ARG ASF_ARCH=x64 ARG STEAM_TOKEN_DUMPER_TOKEN ENV CONFIGURATION Release ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 ENV DOTNET_NOLOGO 1 -ENV NET_CORE_VERSION netcoreapp3.1 +ENV NET_CORE_VERSION net5.0 ENV STEAM_TOKEN_DUMPER_NAME ArchiSteamFarm.OfficialPlugins.SteamTokenDumper WORKDIR /app COPY --from=build-node /app/dist ASF-ui/dist @@ -33,7 +33,7 @@ RUN dotnet --info && \ if [ -d "ArchiSteamFarm/overlay/generic" ]; then cp "ArchiSteamFarm/overlay/generic/"* "out/result"; fi && \ if [ -f "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/${STEAM_TOKEN_DUMPER_NAME}.dll" ]; then mkdir -p "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; cp "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/${STEAM_TOKEN_DUMPER_NAME}.dll" "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; fi -FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim${DOTNET_ARCH} AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim${DOTNET_ARCH} AS runtime ENV ASPNETCORE_URLS= ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 ENV DOTNET_NOLOGO 1 diff --git a/Dockerfile.Service b/Dockerfile.Service index 9bea7a6f4..dac3123a1 100644 --- a/Dockerfile.Service +++ b/Dockerfile.Service @@ -8,13 +8,13 @@ RUN echo "node: $(node --version)" && \ npm ci && \ npm run deploy -FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-dotnet +FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-dotnet ARG ASF_ARCH=x64 ARG STEAM_TOKEN_DUMPER_TOKEN ENV CONFIGURATION Release ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 ENV DOTNET_NOLOGO 1 -ENV NET_CORE_VERSION netcoreapp3.1 +ENV NET_CORE_VERSION net5.0 ENV STEAM_TOKEN_DUMPER_NAME ArchiSteamFarm.OfficialPlugins.SteamTokenDumper WORKDIR /app COPY --from=build-node /app/dist ASF-ui/dist @@ -33,7 +33,7 @@ RUN dotnet --info && \ if [ -d "ArchiSteamFarm/overlay/linux-${ASF_ARCH}" ]; then cp "ArchiSteamFarm/overlay/linux-${ASF_ARCH}/"* "out/result"; fi && \ if [ -f "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/${STEAM_TOKEN_DUMPER_NAME}.dll" ]; then mkdir -p "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; cp "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/${STEAM_TOKEN_DUMPER_NAME}.dll" "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; fi -FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1-buster-slim${DOTNET_ARCH} AS runtime +FROM mcr.microsoft.com/dotnet/runtime-deps:5.0-buster-slim${DOTNET_ARCH} AS runtime ENV ASPNETCORE_URLS= ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 ENV DOTNET_NOLOGO 1 diff --git a/appveyor.yml b/appveyor.yml index 47f0169fc..5d17ea22a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,11 +6,12 @@ image: Visual Studio 2019 configuration: Release clone_depth: 10 environment: - DOTNET_CHANNEL: 3.1 +# DOTNET_CHANNEL: 5.0 DOTNET_CLI_TELEMETRY_OPTOUT: true DOTNET_INSTALL_DIR: C:\Program Files\dotnet DOTNET_NOLOGO: true - NET_CORE_VERSION: netcoreapp3.1 + DOTNET_SDK: 5.0.100 + NET_CORE_VERSION: net5.0 NET_FRAMEWORK_VERSION: net48 NODE_JS_VERSION: lts STEAM_TOKEN_DUMPER_NAME: ArchiSteamFarm.OfficialPlugins.SteamTokenDumper @@ -51,6 +52,13 @@ install: &([scriptblock]::Create((Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1'))) -Channel "$env:DOTNET_CHANNEL" -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath } + + + if ($env:DOTNET_SDK) { + dotnet --info + + &([scriptblock]::Create((Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1'))) -Channel 'Current' -Version "$env:DOTNET_SDK" -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath + } - ps: Install-Product node "$env:NODE_JS_VERSION" before_build: - pwsh: >- diff --git a/cc.sh b/cc.sh index 0d91bc243..6324bbba8 100755 --- a/cc.sh +++ b/cc.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh set -eu -TARGET_FRAMEWORK="netcoreapp3.1" +TARGET_FRAMEWORK="net5.0" MAIN_PROJECT="ArchiSteamFarm" STEAM_TOKEN_DUMPER_NAME="${MAIN_PROJECT}.OfficialPlugins.SteamTokenDumper"