This commit is contained in:
Archi 2023-11-14 20:01:29 +01:00
parent b34f18497d
commit f2ff2f4929
No known key found for this signature in database
GPG key ID: 6B138B4C64555AEA
45 changed files with 156 additions and 616 deletions

View file

@ -5,8 +5,6 @@ on: [push, pull_request]
env:
CONFIGURATION: Release
DOTNET_SDK_VERSION: 8.0
NET_CORE_VERSION: net8.0
NET_FRAMEWORK_VERSION: net481
NODE_JS_VERSION: 'lts/*'
PLUGINS: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.MobileAuthenticator ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
@ -54,8 +52,6 @@ jobs:
include:
- os: ubuntu-latest
variant: generic
- os: windows-latest
variant: generic-netf
- os: ubuntu-latest
variant: linux-arm
- os: ubuntu-latest
@ -131,19 +127,15 @@ jobs:
- name: Prepare for publishing on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
env:
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
shell: bash
run: |
set -euo pipefail
dotnet restore
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -f "$TARGET_FRAMEWORK" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
- name: Prepare for publishing on Windows
if: startsWith(matrix.os, 'windows-')
env:
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
shell: pwsh
run: |
Set-StrictMode -Version Latest
@ -151,7 +143,7 @@ jobs:
$ProgressPreference = 'SilentlyContinue'
dotnet restore
dotnet build ArchiSteamFarm -c "$env:CONFIGURATION" -f "$env:TARGET_FRAMEWORK" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
dotnet build ArchiSteamFarm -c "$env:CONFIGURATION" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
- name: Prepare ArchiSteamFarm.OfficialPlugins.SteamTokenDumper on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
@ -184,13 +176,12 @@ jobs:
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
env:
MAX_JOBS: 4
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
shell: bash
run: |
set -euo pipefail
publish() {
dotnet publish "$1" -c "$CONFIGURATION" -f "$TARGET_FRAMEWORK" -o "out/${1}/${TARGET_FRAMEWORK}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
dotnet publish "$1" -c "$CONFIGURATION" -o "out/${1}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
}
for plugin in $PLUGINS; do
@ -207,7 +198,6 @@ jobs:
if: startsWith(matrix.os, 'windows-')
env:
MAX_JOBS: 4
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
shell: pwsh
run: |
Set-StrictMode -Version Latest
@ -223,7 +213,7 @@ jobs:
Set-Location "$env:GITHUB_WORKSPACE"
dotnet publish "$plugin" -c "$env:CONFIGURATION" -f "$env:TARGET_FRAMEWORK" -o "out\$plugin\$env:TARGET_FRAMEWORK" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
dotnet publish "$plugin" -c "$env:CONFIGURATION" -o "out\$plugin" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
if ($LastExitCode -ne 0) {
throw "Last command failed."
@ -248,7 +238,6 @@ jobs:
- name: Publish ASF-${{ matrix.variant }} on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
env:
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
VARIANT: ${{ matrix.variant }}
shell: bash
run: |
@ -260,13 +249,13 @@ jobs:
variantArgs="-p:PublishSingleFile=true -p:PublishTrimmed=true -r $VARIANT --self-contained"
fi
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$TARGET_FRAMEWORK" -o "out/${VARIANT}" "-p:ASFVariant=${VARIANT}" -p:ContinuousIntegrationBuild=true --no-restore --nologo $variantArgs
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -o "out/${VARIANT}" "-p:ASFVariant=${VARIANT}" -p:ContinuousIntegrationBuild=true --no-restore --nologo $variantArgs
# If we're including official plugins for this framework, copy them to output directory
for plugin in $PLUGINS; do
if [ -d "out/${plugin}/${TARGET_FRAMEWORK}" ]; then
if [ -d "out/${plugin}" ]; then
mkdir -p "out/${VARIANT}/plugins/${plugin}"
cp -pR "out/${plugin}/${TARGET_FRAMEWORK}/"* "out/${VARIANT}/plugins/${plugin}"
cp -pR "out/${plugin}/"* "out/${VARIANT}/plugins/${plugin}"
fi
done
@ -328,7 +317,6 @@ jobs:
- name: Publish ASF-${{ matrix.variant }} on Windows
if: startsWith(matrix.os, 'windows-')
env:
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
VARIANT: ${{ matrix.variant }}
shell: pwsh
run: |
@ -342,7 +330,7 @@ jobs:
$variantArgs = '-p:PublishSingleFile=true', '-p:PublishTrimmed=true', '-r', "$env:VARIANT", '--self-contained'
}
dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -f "$env:TARGET_FRAMEWORK" -o "out\$env:VARIANT" "-p:ASFVariant=$env:VARIANT" -p:ContinuousIntegrationBuild=true --no-restore --nologo $variantArgs
dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -o "out\$env:VARIANT" "-p:ASFVariant=$env:VARIANT" -p:ContinuousIntegrationBuild=true --no-restore --nologo $variantArgs
if ($LastExitCode -ne 0) {
throw "Last command failed."
@ -350,12 +338,12 @@ jobs:
# If we're including official plugins for this framework, copy them to output directory
foreach ($plugin in $env:PLUGINS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
if (Test-Path "out\$plugin\$env:TARGET_FRAMEWORK" -PathType Container) {
if (Test-Path "out\$plugin" -PathType Container) {
if (!(Test-Path "out\$env:VARIANT\plugins\$plugin" -PathType Container)) {
New-Item -ItemType Directory -Path "out\$env:VARIANT\plugins\$plugin" > $null
}
Copy-Item "out\$plugin\$env:TARGET_FRAMEWORK\*" "out\$env:VARIANT\plugins\$plugin" -Recurse
Copy-Item "out\$plugin\*" "out\$env:VARIANT\plugins\$plugin" -Recurse
}
}
@ -430,12 +418,6 @@ jobs:
name: ubuntu-latest_ASF-generic
path: out
- name: Download ASF-generic-netf artifact from windows-latest
uses: actions/download-artifact@v3.0.2
with:
name: windows-latest_ASF-generic-netf
path: out
- name: Download ASF-linux-arm artifact from ubuntu-latest
uses: actions/download-artifact@v3.0.2
with:

View file

@ -11,13 +11,6 @@
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
</ItemGroup>

View file

@ -9,11 +9,6 @@
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
</ItemGroup>

View file

@ -11,17 +11,6 @@
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481'">
<Reference Include="System.Net.Http" HintPath="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8.1\System.Net.Http.dll" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
</ItemGroup>

View file

@ -13,15 +13,6 @@
<PackageReference Include="System.Linq.Async" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481'">
<Reference Include="System.Net.Http" HintPath="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8.1\System.Net.Http.dll" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
</ItemGroup>

View file

@ -342,8 +342,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ListingAnnouncing, Bot.SteamID, nickname ?? Bot.SteamID.ToString(CultureInfo.InvariantCulture), assetsForListing.Count));
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
BasicResponse? response = await Backend.AnnounceForListing(Bot.SteamID, WebBrowser, assetsForListing, acceptedMatchableTypes, (uint) inventory.Count, matchEverything, tradeToken!, nickname, avatarHash).ConfigureAwait(false);
BasicResponse? response = await Backend.AnnounceForListing(Bot.SteamID, WebBrowser, assetsForListing, acceptedMatchableTypes, (uint) inventory.Count, matchEverything, tradeToken, nickname, avatarHash).ConfigureAwait(false);
if (response == null) {
// This is actually a network failure, so we'll stop sending heartbeats but not record it as valid check
@ -383,12 +382,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
LastAnnouncement = DateTime.UtcNow.AddYears(1);
return;
#if NETFRAMEWORK || NETSTANDARD
case (HttpStatusCode) 429:
#else
case HttpStatusCode.TooManyRequests:
#endif
// ArchiNet told us to try again later
LastAnnouncement = DateTime.UtcNow.AddDays(1);
@ -682,7 +676,6 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
(HttpStatusCode StatusCode, ImmutableHashSet<ListedUser> Users)? response = await Backend.GetListedUsersForMatching(ASF.GlobalConfig.LicenseID.Value, Bot, WebBrowser, ourInventory.Values, acceptedMatchableTypes).ConfigureAwait(false);
if (response == null) {

View file

@ -11,11 +11,6 @@
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
</ItemGroup>

View file

@ -157,8 +157,7 @@ internal static class Commands {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(mobileAuthenticator.GenerateTokenForTime)));
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
CTwoFactor_FinalizeAddAuthenticator_Response? response = await mobileAuthenticatorHandler.FinalizeAuthenticator(bot.SteamID, activationCode, code!, steamTime).ConfigureAwait(false);
CTwoFactor_FinalizeAddAuthenticator_Response? response = await mobileAuthenticatorHandler.FinalizeAuthenticator(bot.SteamID, activationCode, code, steamTime).ConfigureAwait(false);
if (response == null) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(mobileAuthenticatorHandler.FinalizeAuthenticator)));

View file

@ -12,11 +12,6 @@
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
</ItemGroup>

View file

@ -621,12 +621,7 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotC
GlobalCache.Reset(true);
break;
#if NETFRAMEWORK || NETSTANDARD
case (HttpStatusCode) 429:
#else
case HttpStatusCode.TooManyRequests:
#endif
// SteamDB told us to try again later
#pragma warning disable CA5394 // This call isn't used in a security-sensitive manner
TimeSpan startIn = TimeSpan.FromMinutes(Random.Shared.Next(SharedInfo.MinimumMinutesBeforeFirstUpload, SharedInfo.MaximumMinutesBeforeFirstUpload));

View file

@ -23,32 +23,8 @@
<PackageReference Include="System.Composition" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" />
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="zxcvbn-core" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'net481'">
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="Microsoft.AspNetCore.Cors" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" />
<PackageReference Include="Microsoft.AspNetCore.HttpOverrides" />
<PackageReference Include="Microsoft.AspNetCore.ResponseCaching" />
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481'">
<Reference Include="System.Net.Http" HintPath="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8.1\System.Net.Http.dll" />
<Reference Include="System.Security" HintPath="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8.1\System.Security.dll" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="System.IO.FileSystem.AccessControl" />
<PackageReference Include="zxcvbn-core" />
</ItemGroup>
<ItemGroup>

View file

@ -268,7 +268,7 @@ public static class ASF {
}
string targetFile = $"{SharedInfo.ASF}-{SharedInfo.BuildInfo.Variant}.zip";
GitHub.ReleaseResponse.Asset? binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name!.Equals(targetFile, StringComparison.OrdinalIgnoreCase));
GitHub.ReleaseResponse.Asset? binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(targetFile, StringComparison.OrdinalIgnoreCase));
if (binaryAsset == null) {
ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssetForThisVersion);
@ -298,7 +298,7 @@ public static class ASF {
}
if (!string.IsNullOrEmpty(releaseResponse.ChangelogPlainText)) {
ArchiLogger.LogGenericInfo(releaseResponse.ChangelogPlainText!);
ArchiLogger.LogGenericInfo(releaseResponse.ChangelogPlainText);
}
ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.UpdateDownloadingNewVersion, newVersion, binaryAsset.Size / 1024 / 1024));
@ -310,7 +310,7 @@ public static class ASF {
BinaryResponse? response;
try {
response = await WebBrowser.UrlGetToBinary(binaryAsset.DownloadURL!, progressReporter: progressReporter).ConfigureAwait(false);
response = await WebBrowser.UrlGetToBinary(binaryAsset.DownloadURL, progressReporter: progressReporter).ConfigureAwait(false);
} finally {
progressReporter.ProgressChanged -= OnProgressChanged;
}
@ -404,7 +404,6 @@ public static class ASF {
private static HashSet<string> GetLoadedAssembliesNames() {
Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
return loadedAssemblies.Select(static loadedAssembly => loadedAssembly.FullName).Where(static name => !string.IsNullOrEmpty(name)).ToHashSet(StringComparer.Ordinal)!;
}
@ -1018,10 +1017,8 @@ public static class ASF {
return false;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!Directory.Exists(directory!)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
Directory.CreateDirectory(directory!);
if (!Directory.Exists(directory)) {
Directory.CreateDirectory(directory);
}
// We're not interested in extracting placeholder files (but we still want directories created for them, done above)

View file

@ -30,12 +30,6 @@ internal static partial class GeneratedRegexes {
private const string DigitsPattern = @"\d+";
private const string NonAsciiPattern = @"[^\u0000-\u007F]+";
#if NETFRAMEWORK || NETSTANDARD
internal static Regex CdKey() => new(CdKeyPattern, DefaultOptions);
internal static Regex Decimal() => new(DecimalPattern, DefaultOptions);
internal static Regex Digits() => new(DigitsPattern, DefaultOptions);
internal static Regex NonAscii() => new(NonAsciiPattern, DefaultOptions);
#else
[GeneratedRegex(CdKeyPattern, DefaultOptions)]
internal static partial Regex CdKey();
@ -47,5 +41,4 @@ internal static partial class GeneratedRegexes {
[GeneratedRegex(NonAsciiPattern, DefaultOptions)]
internal static partial Regex NonAscii();
#endif
}

View file

@ -29,67 +29,37 @@ internal static partial class NativeMethods {
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("Windows")]
[return: MarshalAs(UnmanagedType.Bool)]
#if NETFRAMEWORK || NETSTANDARD
[DllImport("kernel32.dll")]
internal static extern bool GetConsoleMode(nint hConsoleHandle, out EConsoleMode lpMode);
#else
[LibraryImport("kernel32.dll")]
internal static partial bool GetConsoleMode(nint hConsoleHandle, out EConsoleMode lpMode);
#endif
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("FreeBSD")]
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("MacOS")]
#if NETFRAMEWORK || NETSTANDARD
[DllImport("libc", EntryPoint = "geteuid", SetLastError = true)]
internal static extern uint GetEuid();
#else
[LibraryImport("libc", EntryPoint = "geteuid", SetLastError = true)]
internal static partial uint GetEuid();
#endif
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("Windows")]
#if NETFRAMEWORK || NETSTANDARD
[DllImport("kernel32.dll")]
internal static extern nint GetStdHandle(EStandardHandle nStdHandle);
#else
[LibraryImport("kernel32.dll")]
internal static partial nint GetStdHandle(EStandardHandle nStdHandle);
#endif
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("Windows")]
[return: MarshalAs(UnmanagedType.Bool)]
#if NETFRAMEWORK || NETSTANDARD
[DllImport("kernel32.dll")]
internal static extern bool SetConsoleMode(nint hConsoleHandle, EConsoleMode dwMode);
#else
[LibraryImport("kernel32.dll")]
internal static partial bool SetConsoleMode(nint hConsoleHandle, EConsoleMode dwMode);
#endif
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("Windows")]
#if NETFRAMEWORK || NETSTANDARD
[DllImport("kernel32.dll")]
internal static extern EExecutionState SetThreadExecutionState(EExecutionState executionState);
#else
[LibraryImport("kernel32.dll")]
internal static partial EExecutionState SetThreadExecutionState(EExecutionState executionState);
#endif
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("Windows")]
[return: MarshalAs(UnmanagedType.Bool)]
#if NETFRAMEWORK || NETSTANDARD
[DllImport("user32.dll")]
internal static extern void ShowWindow(nint hWnd, EShowWindow nCmdShow);
#else
[LibraryImport("user32.dll")]
internal static partial void ShowWindow(nint hWnd, EShowWindow nCmdShow);
#endif
[Flags]
[SupportedOSPlatform("Windows")]

View file

@ -43,22 +43,17 @@ internal static class OS {
internal static readonly string ProcessFileName = Environment.ProcessPath ?? throw new InvalidOperationException(nameof(ProcessFileName));
internal static DateTime ProcessStartTime {
#if NETFRAMEWORK || NETSTANDARD
get => RuntimeMadness.ProcessStartTime.ToUniversalTime();
#else
get {
using Process process = Process.GetCurrentProcess();
return process.StartTime.ToUniversalTime();
}
#endif
}
internal static string Version {
get {
if (!string.IsNullOrEmpty(BackingVersion)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
return BackingVersion!;
return BackingVersion;
}
string framework = RuntimeInformation.FrameworkDescription.Trim();
@ -67,15 +62,11 @@ internal static class OS {
framework = "Unknown Framework";
}
#if NETFRAMEWORK || NETSTANDARD
string runtime = RuntimeInformation.OSArchitecture.ToString();
#else
string runtime = RuntimeInformation.RuntimeIdentifier.Trim();
if (runtime.Length == 0) {
runtime = "Unknown Runtime";
}
#endif
string description = RuntimeInformation.OSDescription.Trim();
@ -210,38 +201,6 @@ internal static class OS {
return true;
}
if (SharedInfo.BuildInfo.Variant.EndsWith("-netf", StringComparison.Ordinal)) {
#if NETFRAMEWORK || NETSTANDARD
// All Windows variants (7+) have valid .NET Core build
if (OperatingSystem.IsWindows()) {
return false;
}
// Non-Windows variants of generic-netf are supported only in Mono
if (!RuntimeMadness.IsRunningOnMono) {
return false;
}
// Platforms not supported by .NET Core
return RuntimeInformation.OSArchitecture switch {
// Sadly we can't tell a difference between ARMv6 and ARMv7 reliably, we'll believe that this linux-arm user knows what he's doing and he's indeed in need of generic-netf on ARMv6
Architecture.Arm => true,
// Apart from real x86, this also covers all unknown architectures, such as sparc, ppc64, and anything else Mono might support, we're fine with that
Architecture.X86 => true,
// Everything else is covered by .NET Core
_ => false
};
#else
// .NET Framework build running on .NET Core? Very funny - only if somebody lied during build process
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(SharedInfo.BuildInfo.Variant), SharedInfo.BuildInfo.Variant));
return false;
#endif
}
if (SharedInfo.BuildInfo.Variant == "generic") {
// Generic is supported everywhere
return true;

View file

@ -81,11 +81,7 @@ public static class Utilities {
CookieCollection cookies = cookieContainer.GetCookies(uri);
#if NETFRAMEWORK || NETSTANDARD
return cookies.Count > 0 ? (from Cookie cookie in cookies where cookie.Name == name select cookie.Value).FirstOrDefault() : null;
#else
return cookies.Count > 0 ? cookies.FirstOrDefault(cookie => cookie.Name == name)?.Value : null;
#endif
}
[PublicAPI]

View file

@ -173,10 +173,8 @@ internal sealed class CrossProcessFileBasedSemaphore : IAsyncDisposable, ICrossP
return;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!Directory.Exists(directoryPath!)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
DirectoryInfo directoryInfo = Directory.CreateDirectory(directoryPath!);
if (!Directory.Exists(directoryPath)) {
DirectoryInfo directoryInfo = Directory.CreateDirectory(directoryPath);
if (OperatingSystem.IsWindows()) {
try {

View file

@ -81,11 +81,15 @@ public abstract class SerializableFile : IDisposable {
string json = JsonConvert.SerializeObject(this, Debugging.IsUserDebugging ? Formatting.Indented : Formatting.None);
if (string.IsNullOrEmpty(json)) {
throw new InvalidOperationException(nameof(json));
}
// We always want to write entire content to temporary file first, in order to never load corrupted data, also when target file doesn't exist
string newFilePath = $"{FilePath}.new";
if (File.Exists(FilePath)) {
string currentJson = await File.ReadAllTextAsync(FilePath!).ConfigureAwait(false);
string currentJson = await File.ReadAllTextAsync(FilePath).ConfigureAwait(false);
if (json == currentJson) {
return;
@ -93,11 +97,11 @@ public abstract class SerializableFile : IDisposable {
await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false);
File.Replace(newFilePath, FilePath!, null);
File.Replace(newFilePath, FilePath, null);
} else {
await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false);
File.Move(newFilePath, FilePath!);
File.Move(newFilePath, FilePath);
}
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
@ -125,8 +129,13 @@ public abstract class SerializableFile : IDisposable {
}
internal static async Task<bool> Write(string filePath, string json) {
ArgumentException.ThrowIfNullOrEmpty(filePath);
ArgumentException.ThrowIfNullOrEmpty(json);
if (string.IsNullOrEmpty(filePath)) {
throw new ArgumentNullException(nameof(filePath));
}
if (string.IsNullOrEmpty(json)) {
throw new ArgumentNullException(nameof(json));
}
string newFilePath = $"{filePath}.new";

View file

@ -19,10 +19,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#if NETFRAMEWORK || NETSTANDARD
using IHost = Microsoft.AspNetCore.Hosting.IWebHost;
using HostBuilder = Microsoft.AspNetCore.Hosting.WebHostBuilder;
#endif
using System;
using System.IO;
using System.Threading.Tasks;

View file

@ -186,6 +186,6 @@ public sealed class ASFController : ArchiController {
message = success ? Strings.Success : Strings.WarningFailed;
}
return Ok(new GenericResponse<string>(success, message!, version?.ToString()));
return Ok(new GenericResponse<string>(success, message, version?.ToString()));
}
}

View file

@ -62,10 +62,8 @@ public sealed class CommandController : ArchiController {
string command = request.Command;
string? commandPrefix = ASF.GlobalConfig != null ? ASF.GlobalConfig.CommandPrefix : GlobalConfig.DefaultCommandPrefix;
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!string.IsNullOrEmpty(commandPrefix) && command.StartsWith(commandPrefix!, StringComparison.Ordinal)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (command.Length == commandPrefix!.Length) {
if (!string.IsNullOrEmpty(commandPrefix) && command.StartsWith(commandPrefix, StringComparison.Ordinal)) {
if (command.Length == commandPrefix.Length) {
// If the message starts with command prefix and is of the same length as command prefix, then it's just empty command trigger, useless
return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(command))));
}

View file

@ -96,7 +96,7 @@ public sealed class NLogController : ArchiController {
}
if (!HttpContext.WebSockets.IsWebSocketRequest) {
return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError!, $"{nameof(HttpContext.WebSockets.IsWebSocketRequest)}: {HttpContext.WebSockets.IsWebSocketRequest}")));
return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(HttpContext.WebSockets.IsWebSocketRequest)}: {HttpContext.WebSockets.IsWebSocketRequest}")));
}
// From now on we can return only EmptyResult as the response stream is already being used by existing websocket connection

View file

@ -67,8 +67,7 @@ public sealed class TypeController : ArchiController {
string? unifiedName = field.FieldType.GetUnifiedName();
if (!string.IsNullOrEmpty(unifiedName)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
body[jsonProperty.PropertyName ?? field.Name] = unifiedName!;
body[jsonProperty.PropertyName ?? field.Name] = unifiedName;
}
}
}
@ -80,8 +79,7 @@ public sealed class TypeController : ArchiController {
string? unifiedName = property.PropertyType.GetUnifiedName();
if (!string.IsNullOrEmpty(unifiedName)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
body[jsonProperty.PropertyName ?? property.Name] = unifiedName!;
body[jsonProperty.PropertyName ?? property.Name] = unifiedName;
}
}
}
@ -104,10 +102,7 @@ public sealed class TypeController : ArchiController {
continue;
}
// ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework
body[valueText!] = valueObjText!;
// ReSharper restore RedundantSuppressNullableWarningExpression - required for .NET Framework
body[valueText] = valueObjText;
}
}

View file

@ -19,9 +19,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#if NETFRAMEWORK || NETSTANDARD
using MvcNewtonsoftJsonOptions = Microsoft.AspNetCore.Mvc.MvcJsonOptions;
#endif
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

View file

@ -63,9 +63,7 @@ public class GenericResponse {
public GenericResponse(bool success, string? message = null) {
Success = success;
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
Message = !string.IsNullOrEmpty(message) ? message! : success ? "OK" : Strings.WarningFailed;
Message = !string.IsNullOrEmpty(message) ? message : success ? "OK" : Strings.WarningFailed;
}
[JsonConstructor]

View file

@ -19,12 +19,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#if NETFRAMEWORK || NETSTANDARD
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Converters;
using IWebHostEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment;
using IMvcBuilder = Microsoft.Extensions.DependencyInjection.IMvcCoreBuilder;
#endif
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@ -126,8 +120,7 @@ internal sealed class Startup {
continue;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
physicalPath = Path.Combine(assemblyDirectory!, plugin.PhysicalPath);
physicalPath = Path.Combine(assemblyDirectory, plugin.PhysicalPath);
}
if (!Directory.Exists(physicalPath)) {
@ -162,9 +155,7 @@ internal sealed class Startup {
);
// Use routing for our API controllers, this should be called once we're done with all the static files mess
#if !NETFRAMEWORK && !NETSTANDARD
app.UseRouting();
#endif
// We want to protect our API with IPCPassword and additional security, this should be called after routing, so the middleware won't have to deal with API endpoints that do not exist
app.UseWhen(static context => context.Request.Path.StartsWithSegments("/Api", StringComparison.OrdinalIgnoreCase), static appBuilder => appBuilder.UseMiddleware<ApiAuthenticationMiddleware>());
@ -181,11 +172,7 @@ internal sealed class Startup {
app.UseWebSockets();
// Finally register proper API endpoints once we're done with routing
#if NETFRAMEWORK || NETSTANDARD
app.UseMvcWithDefaultRoute();
#else
app.UseEndpoints(static endpoints => endpoints.MapControllers());
#endif
// Add support for swagger, responsible for automatic API documentation generation, this should be on the end, once we're done with API
app.UseSwagger();
@ -341,17 +328,6 @@ internal sealed class Startup {
mvc.AddControllersAsServices();
#if NETFRAMEWORK || NETSTANDARD
// Use latest compatibility version for MVC
mvc.SetCompatibilityVersion(CompatibilityVersion.Latest);
// Add standard formatters
mvc.AddFormatterMappings();
// Add API explorer for swagger
mvc.AddApiExplorer();
#endif
mvc.AddNewtonsoftJson(
static options => {
// Fix default contract resolver to use original names and not a camel case
@ -360,11 +336,6 @@ internal sealed class Startup {
if (Debugging.IsUserDebugging) {
options.SerializerSettings.Formatting = Formatting.Indented;
}
#if NETFRAMEWORK || NETSTANDARD
// .NET Framework serializes Version as object by default, serialize it as string just like .NET Core
options.SerializerSettings.Converters.Add(new VersionConverter());
#endif
}
);
}

View file

@ -19,10 +19,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#if NETFRAMEWORK || NETSTANDARD
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
#endif
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
@ -35,26 +31,6 @@ using Newtonsoft.Json;
namespace ArchiSteamFarm.IPC;
internal static class WebUtilities {
#if NETFRAMEWORK || NETSTANDARD
internal static IMvcCoreBuilder AddControllers(this IServiceCollection services) {
ArgumentNullException.ThrowIfNull(services);
return services.AddMvcCore();
}
internal static IMvcCoreBuilder AddNewtonsoftJson(this IMvcCoreBuilder mvc, Action<MvcJsonOptions> setupAction) {
ArgumentNullException.ThrowIfNull(mvc);
ArgumentNullException.ThrowIfNull(setupAction);
// Add JSON formatters that will be used as default ones if no specific formatters are asked for
mvc.AddJsonFormatters();
mvc.AddJsonOptions(setupAction);
return mvc;
}
#endif
internal static string? GetUnifiedName(this Type type) {
ArgumentNullException.ThrowIfNull(type);

View file

@ -106,8 +106,7 @@ internal static class Logging {
Console.Write(Bot.FormatBotResponse(Strings.UserInputDeviceConfirmation, botName));
result = ConsoleReadLine();
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (string.IsNullOrEmpty(result) || result!.Equals("Y", StringComparison.OrdinalIgnoreCase) || result.Equals("N", StringComparison.OrdinalIgnoreCase)) {
if (string.IsNullOrEmpty(result) || result.Equals("Y", StringComparison.OrdinalIgnoreCase) || result.Equals("N", StringComparison.OrdinalIgnoreCase)) {
break;
}
}
@ -159,8 +158,7 @@ internal static class Logging {
ConsoleSemaphore.Release();
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
return !string.IsNullOrEmpty(result) ? result!.Trim() : null;
return !string.IsNullOrEmpty(result) ? result.Trim() : null;
}
internal static void InitCoreLoggers(bool uniqueInstance) {
@ -383,12 +381,8 @@ internal static class Logging {
string? commandPrefix = ASF.GlobalConfig != null ? ASF.GlobalConfig.CommandPrefix : GlobalConfig.DefaultCommandPrefix;
// ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!string.IsNullOrEmpty(commandPrefix) && command!.StartsWith(commandPrefix!, StringComparison.Ordinal)) {
// ReSharper restore RedundantSuppressNullableWarningExpression - required for .NET Framework
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (command.Length == commandPrefix!.Length) {
if (!string.IsNullOrEmpty(commandPrefix) && command.StartsWith(commandPrefix, StringComparison.Ordinal)) {
if (command.Length == commandPrefix.Length) {
// If the message starts with command prefix and is of the same length as command prefix, then it's just empty command trigger, useless
continue;
}
@ -406,8 +400,7 @@ internal static class Logging {
Console.WriteLine($@"<> {Strings.Executing}");
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
string? response = await targetBot.Commands.Response(EAccess.Owner, command!).ConfigureAwait(false);
string? response = await targetBot.Commands.Response(EAccess.Owner, command).ConfigureAwait(false);
if (string.IsNullOrEmpty(response)) {
ASF.ArchiLogger.LogNullError(response);

View file

@ -78,8 +78,7 @@ internal sealed class SteamTarget : AsyncTaskTarget {
string? botName = BotName?.Render(logEvent);
if (!string.IsNullOrEmpty(botName)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
bot = Bot.GetBot(botName!);
bot = Bot.GetBot(botName);
if (bot?.IsConnectedAndLoggedOn != true) {
return;

View file

@ -66,10 +66,9 @@ public static class PluginsCore {
// At the same time it'd be the best if we avoided all special characters, such as '/' found e.g. in base64, as we can't be sure that it's not a prohibited character in regards to native OS implementation
// Because of that, SHA256 is sufficient for our case, as it generates alphanumeric characters only, and is barely 256-bit long. We don't need any kind of complex cryptography or collision detection here, any hashing will do, and the shorter the better
if (!string.IsNullOrEmpty(Program.NetworkGroup)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
objectName += $"-{Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(Program.NetworkGroup!)))}";
objectName += $"-{Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(Program.NetworkGroup)))}";
} else if (!string.IsNullOrEmpty(ASF.GlobalConfig.WebProxyText)) {
objectName += $"-{Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(ASF.GlobalConfig.WebProxyText!)))}";
objectName += $"-{Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(ASF.GlobalConfig.WebProxyText)))}";
}
string resourceName = OS.GetOsResourceName(objectName);

View file

@ -26,6 +26,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Quic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
@ -42,9 +43,6 @@ using ArchiSteamFarm.Web;
using Newtonsoft.Json;
using NLog;
using SteamKit2;
#if !NETFRAMEWORK && !NETSTANDARD
using System.Net.Quic;
#endif
namespace ArchiSteamFarm;
@ -58,15 +56,9 @@ internal static class Program {
internal static bool ShutdownSequenceInitialized { get; private set; }
internal static bool SteamParentalGeneration { get; private set; } = true;
#if !NETFRAMEWORK && !NETSTANDARD
private static readonly Dictionary<PosixSignal, PosixSignalRegistration> RegisteredPosixSignals = new();
#endif
private static readonly TaskCompletionSource<byte> ShutdownResetEvent = new();
#if !NETFRAMEWORK && !NETSTANDARD
private static readonly ImmutableHashSet<PosixSignal> SupportedPosixSignals = ImmutableHashSet.Create(PosixSignal.SIGINT, PosixSignal.SIGTERM);
#endif
private static bool IgnoreUnsupportedEnvironment;
private static bool InputCryptkeyManually;
@ -182,15 +174,11 @@ internal static class Program {
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
#if NETFRAMEWORK || NETSTANDARD
RuntimeMadness.Initialize();
#else
if (OperatingSystem.IsFreeBSD() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) {
foreach (PosixSignal signal in SupportedPosixSignals) {
RegisteredPosixSignals[signal] = PosixSignalRegistration.Create(signal, OnPosixSignal);
}
}
#endif
Console.CancelKeyPress += OnCancelKeyPress;
@ -304,8 +292,7 @@ internal static class Program {
string? copyright = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyCopyrightAttribute>()?.Copyright;
if (!string.IsNullOrEmpty(copyright)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
ASF.ArchiLogger.LogGenericInfo(copyright!);
ASF.ArchiLogger.LogGenericInfo(copyright);
}
if (IgnoreUnsupportedEnvironment) {
@ -333,8 +320,7 @@ internal static class Program {
return false;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
ArchiCryptoHelper.SetEncryptionKey(cryptkey!);
ArchiCryptoHelper.SetEncryptionKey(cryptkey);
}
if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
@ -378,7 +364,7 @@ internal static class Program {
if (!string.IsNullOrEmpty(globalConfig.CurrentCulture)) {
try {
// GetCultureInfo() would be better but we can't use it for specifying neutral cultures such as "en"
CultureInfo culture = CultureInfo.CreateSpecificCulture(globalConfig.CurrentCulture!);
CultureInfo culture = CultureInfo.CreateSpecificCulture(globalConfig.CurrentCulture);
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = culture;
} catch (Exception e) {
ASF.ArchiLogger.LogGenericWarningException(e);
@ -393,8 +379,7 @@ internal static class Program {
if (!string.IsNullOrEmpty(latestJson)) {
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.AutomaticFileMigration, globalConfigFile));
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
await SerializableFile.Write(globalConfigFile, latestJson!).ConfigureAwait(false);
await SerializableFile.Write(globalConfigFile, latestJson).ConfigureAwait(false);
ASF.ArchiLogger.LogGenericInfo(Strings.Done);
}
@ -477,7 +462,6 @@ internal static class Program {
ShutdownSequenceInitialized = true;
#if !NETFRAMEWORK && !NETSTANDARD
if (OperatingSystem.IsFreeBSD() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) {
// Unregister from registered signals
foreach (PosixSignalRegistration registration in RegisteredPosixSignals.Values) {
@ -486,7 +470,6 @@ internal static class Program {
RegisteredPosixSignals.Clear();
}
#endif
// Sockets created by IPC might still be running for a short while after complete app shutdown
// Ensure that IPC is stopped before we finalize shutdown sequence
@ -522,7 +505,6 @@ internal static class Program {
private static async void OnCancelKeyPress(object? sender, ConsoleCancelEventArgs e) => await Exit(130).ConfigureAwait(false);
#if !NETFRAMEWORK && !NETSTANDARD
private static async void OnPosixSignal(PosixSignalContext signal) {
ArgumentNullException.ThrowIfNull(signal);
@ -539,7 +521,6 @@ internal static class Program {
throw new InvalidOperationException(nameof(signal.Signal));
}
}
#endif
private static async void OnProcessExit(object? sender, EventArgs e) => await Shutdown().ConfigureAwait(false);
@ -695,15 +676,13 @@ internal static class Program {
string? envCryptKey = Environment.GetEnvironmentVariable(SharedInfo.EnvironmentVariableCryptKey);
if (!string.IsNullOrEmpty(envCryptKey)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
HandleCryptKeyArgument(envCryptKey!);
HandleCryptKeyArgument(envCryptKey);
}
string? envCryptKeyFile = Environment.GetEnvironmentVariable(SharedInfo.EnvironmentVariableCryptKeyFile);
if (!string.IsNullOrEmpty(envCryptKeyFile)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!await HandleCryptKeyFileArgument(envCryptKeyFile!).ConfigureAwait(false)) {
if (!await HandleCryptKeyFileArgument(envCryptKeyFile).ConfigureAwait(false)) {
return false;
}
}
@ -711,15 +690,13 @@ internal static class Program {
string? envNetworkGroup = Environment.GetEnvironmentVariable(SharedInfo.EnvironmentVariableNetworkGroup);
if (!string.IsNullOrEmpty(envNetworkGroup)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
HandleNetworkGroupArgument(envNetworkGroup!);
HandleNetworkGroupArgument(envNetworkGroup);
}
string? envPath = Environment.GetEnvironmentVariable(SharedInfo.EnvironmentVariablePath);
if (!string.IsNullOrEmpty(envPath)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!HandlePathArgument(envPath!)) {
if (!HandlePathArgument(envPath)) {
return false;
}
}

View file

@ -80,8 +80,7 @@ public static class SharedInfo {
internal static string HomeDirectory {
get {
if (!string.IsNullOrEmpty(CachedHomeDirectory)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
return CachedHomeDirectory!;
return CachedHomeDirectory;
}
// We're aiming to handle two possible cases here, classic publish and single-file publish which is possible with OS-specific builds
@ -110,9 +109,6 @@ public static class SharedInfo {
#elif ASF_VARIANT_GENERIC
internal static bool CanUpdate => true;
internal static string Variant => "generic";
#elif ASF_VARIANT_GENERIC_NETF
internal static bool CanUpdate => true;
internal static string Variant => "generic-netf";
#elif ASF_VARIANT_LINUX_ARM
internal static bool CanUpdate => true;
internal static string Variant => "linux-arm";

View file

@ -270,8 +270,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
return;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
JwtSecurityToken? jwtToken = Utilities.ReadJwtToken(value!);
JwtSecurityToken? jwtToken = Utilities.ReadJwtToken(value);
if (jwtToken == null) {
return;
@ -1124,7 +1123,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
break;
}
if (packageData.ProhibitRunInCountries.Contains(IPCountryCode!)) {
if (packageData.ProhibitRunInCountries.Contains(IPCountryCode)) {
// We are restricted by this package, we can only be saved by another package that is not restricted
DateTime regionRestrictedUntilPackage = ownedPackageData.TimeCreated.AddMonths(RegionRestrictionPlayableBlockMonths);
@ -1195,8 +1194,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
if (!string.IsNullOrEmpty(releaseState)) {
// We must convert this to uppercase, since Valve doesn't stick to any convention and we can have a case mismatch
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
switch (releaseState!.ToUpperInvariant()) {
switch (releaseState.ToUpperInvariant()) {
case "RELEASED":
break;
case "PRELOADONLY" or "PRERELEASE":
@ -1215,8 +1213,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
}
// We must convert this to uppercase, since Valve doesn't stick to any convention and we can have a case mismatch
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
switch (type!.ToUpperInvariant()) {
switch (type.ToUpperInvariant()) {
case "APPLICATION" or "EPISODE" or "GAME" or "MOD" or "MOVIE" or "SERIES" or "TOOL" or "VIDEO":
// Types that can be idled
return (appID, DateTime.MinValue, true);
@ -1239,8 +1236,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
return (appID, DateTime.MinValue, true);
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
string[] dlcAppIDsTexts = listOfDlc!.Split(SharedInfo.ListElementSeparators, StringSplitOptions.RemoveEmptyEntries);
string[] dlcAppIDsTexts = listOfDlc.Split(SharedInfo.ListElementSeparators, StringSplitOptions.RemoveEmptyEntries);
foreach (string dlcAppIDsText in dlcAppIDsTexts) {
if (!uint.TryParse(dlcAppIDsText, out uint dlcAppID) || (dlcAppID == 0)) {
@ -1267,8 +1263,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
return null;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!string.IsNullOrEmpty(ASF.GlobalConfig?.DefaultBot) && Bots.TryGetValue(ASF.GlobalConfig!.DefaultBot!, out Bot? targetBot)) {
if (!string.IsNullOrEmpty(ASF.GlobalConfig?.DefaultBot) && Bots.TryGetValue(ASF.GlobalConfig.DefaultBot, out Bot? targetBot)) {
return targetBot;
}
@ -1350,8 +1345,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? prohibitRunInCountriesText = productInfo.KeyValues["extended"]["prohibitrunincountries"].AsString();
if (!string.IsNullOrEmpty(prohibitRunInCountriesText)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
prohibitRunInCountries = prohibitRunInCountriesText!.Split(' ', StringSplitOptions.RemoveEmptyEntries);
prohibitRunInCountries = prohibitRunInCountriesText.Split(' ', StringSplitOptions.RemoveEmptyEntries);
}
result[productInfo.ID] = new PackageData(changeNumber, validUntil, appIDs?.ToImmutableHashSet(), prohibitRunInCountries?.ToImmutableHashSet(StringComparer.Ordinal));
@ -1390,7 +1384,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? gameName = null;
if (!string.IsNullOrEmpty(BotConfig.CustomGamePlayedWhileFarming)) {
gameName = string.Format(CultureInfo.CurrentCulture, BotConfig.CustomGamePlayedWhileFarming!, game.AppID, game.GameName);
gameName = string.Format(CultureInfo.CurrentCulture, BotConfig.CustomGamePlayedWhileFarming, game.AppID, game.GameName);
}
await ArchiHandler.PlayGames(new HashSet<uint>(1) { game.PlayableAppID }, gameName).ConfigureAwait(false);
@ -1404,7 +1398,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? gameName = null;
if (!string.IsNullOrEmpty(BotConfig.CustomGamePlayedWhileFarming)) {
gameName = string.Format(CultureInfo.CurrentCulture, BotConfig.CustomGamePlayedWhileFarming!, string.Join(", ", games.Select(static game => game.AppID)), string.Join(", ", games.Select(static game => game.GameName)));
gameName = string.Format(CultureInfo.CurrentCulture, BotConfig.CustomGamePlayedWhileFarming, string.Join(", ", games.Select(static game => game.AppID)), string.Join(", ", games.Select(static game => game.GameName)));
}
await ArchiHandler.PlayGames(games.Select(static game => game.PlayableAppID).ToHashSet(), gameName).ConfigureAwait(false);
@ -1570,7 +1564,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
if (!force && !string.IsNullOrEmpty(AccessToken) && AccessTokenValidUntil.HasValue && (AccessTokenValidUntil.Value > now.AddMinutes(MinimumAccessTokenValidityMinutes))) {
// We can use the tokens we already have
if (await ArchiWebHandler.Init(SteamID, SteamClient.Universe, AccessToken!, SteamParentalActive ? BotConfig.SteamParentalCode : null).ConfigureAwait(false)) {
if (await ArchiWebHandler.Init(SteamID, SteamClient.Universe, AccessToken, SteamParentalActive ? BotConfig.SteamParentalCode : null).ConfigureAwait(false)) {
InitRefreshTokensTimer(AccessTokenValidUntil.Value);
return true;
@ -1590,7 +1584,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
AccessTokenGenerateResult response;
try {
response = await SteamClient.Authentication.GenerateAccessTokenForAppAsync(SteamID, RefreshToken!, true).ConfigureAwait(false);
response = await SteamClient.Authentication.GenerateAccessTokenForAppAsync(SteamID, RefreshToken, true).ConfigureAwait(false);
} catch (Exception e) {
// The request has failed, in almost all cases this means our refresh token is no longer valid, relog needed
ArchiLogger.LogGenericWarningException(e);
@ -1666,8 +1660,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
if (!string.IsNullOrEmpty(latestJson)) {
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.AutomaticFileMigration, configFilePath));
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
await SerializableFile.Write(configFilePath, latestJson!).ConfigureAwait(false);
await SerializableFile.Write(configFilePath, latestJson).ConfigureAwait(false);
ASF.ArchiLogger.LogGenericInfo(Strings.Done);
}
@ -1823,8 +1816,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? input = await Logging.GetUserInput(inputType, BotName).ConfigureAwait(false);
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (string.IsNullOrEmpty(input) || !SetUserInput(inputType, input!)) {
if (string.IsNullOrEmpty(input) || !SetUserInput(inputType, input)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(input)));
Stop();
@ -1951,11 +1943,10 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? key = game.Key as string;
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (string.IsNullOrEmpty(key)) {
invalid = true;
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(key)));
} else if (!Utilities.IsValidCdKey(key!)) {
} else if (!Utilities.IsValidCdKey(key)) {
invalid = true;
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, key));
}
@ -2103,8 +2094,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
}
// URIs to foil badges are the same as for normal badges except they end with "?border=1"
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
string appIDText = badgeUri!.Split('?', StringSplitOptions.RemoveEmptyEntries)[0].Split('/', StringSplitOptions.RemoveEmptyEntries)[^1];
string appIDText = badgeUri.Split('?', StringSplitOptions.RemoveEmptyEntries)[0].Split('/', StringSplitOptions.RemoveEmptyEntries)[^1];
if (!uint.TryParse(appIDText, out uint appID) || (appID == 0)) {
ArchiLogger.LogNullError(appID);
@ -2168,8 +2158,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? authCode = await Logging.GetUserInput(ASF.EUserInputType.SteamGuard, BotName).ConfigureAwait(false);
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (string.IsNullOrEmpty(authCode) || !SetUserInput(ASF.EUserInputType.SteamGuard, authCode!)) {
if (string.IsNullOrEmpty(authCode) || !SetUserInput(ASF.EUserInputType.SteamGuard, authCode)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(authCode)));
Stop();
@ -2182,8 +2171,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? twoFactorCode = await Logging.GetUserInput(ASF.EUserInputType.TwoFactorAuthentication, BotName).ConfigureAwait(false);
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (string.IsNullOrEmpty(twoFactorCode) || !SetUserInput(ASF.EUserInputType.TwoFactorAuthentication, twoFactorCode!)) {
if (string.IsNullOrEmpty(twoFactorCode) || !SetUserInput(ASF.EUserInputType.TwoFactorAuthentication, twoFactorCode)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(twoFactorCode)));
Stop();
@ -2335,8 +2323,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? steamLogin = await Logging.GetUserInput(ASF.EUserInputType.Login, BotName).ConfigureAwait(false);
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (string.IsNullOrEmpty(steamLogin) || !SetUserInput(ASF.EUserInputType.Login, steamLogin!)) {
if (string.IsNullOrEmpty(steamLogin) || !SetUserInput(ASF.EUserInputType.Login, steamLogin)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(steamLogin)));
return false;
@ -2351,8 +2338,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? steamPassword = await Logging.GetUserInput(ASF.EUserInputType.Password, BotName).ConfigureAwait(false);
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (string.IsNullOrEmpty(steamPassword) || !SetUserInput(ASF.EUserInputType.Password, steamPassword!)) {
if (string.IsNullOrEmpty(steamPassword) || !SetUserInput(ASF.EUserInputType.Password, steamPassword)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(steamPassword)));
return false;
@ -2380,13 +2366,11 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
if (BotConfig.PasswordFormat.HasTransformation()) {
if (!string.IsNullOrEmpty(accessToken)) {
// ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework
accessToken = await ArchiCryptoHelper.Decrypt(BotConfig.PasswordFormat, accessToken!).ConfigureAwait(false);
accessToken = await ArchiCryptoHelper.Decrypt(BotConfig.PasswordFormat, accessToken).ConfigureAwait(false);
}
if (!string.IsNullOrEmpty(refreshToken)) {
// ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework
refreshToken = await ArchiCryptoHelper.Decrypt(BotConfig.PasswordFormat, refreshToken!).ConfigureAwait(false);
refreshToken = await ArchiCryptoHelper.Decrypt(BotConfig.PasswordFormat, refreshToken).ConfigureAwait(false);
}
}
@ -2621,7 +2605,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
}
// Steam login and password fields can contain ASCII characters only, including spaces
string username = GeneratedRegexes.NonAscii().Replace(BotConfig.SteamLogin!, "");
string username = GeneratedRegexes.NonAscii().Replace(BotConfig.SteamLogin, "");
if (string.IsNullOrEmpty(username)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(BotConfig.SteamLogin)));
@ -2634,8 +2618,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
string? password = await BotConfig.GetDecryptedSteamPassword().ConfigureAwait(false);
if (!string.IsNullOrEmpty(password)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
password = GeneratedRegexes.NonAscii().Replace(password!, "");
password = GeneratedRegexes.NonAscii().Replace(password, "");
if (string.IsNullOrEmpty(password)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(BotConfig.SteamPassword)));
@ -3190,8 +3173,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
if (!string.IsNullOrEmpty(steamParentalCode)) {
// We were able to automatically generate it, potentially with help of the config
if (BotConfig.SteamParentalCode != steamParentalCode) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode!)) {
if (!SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(steamParentalCode)));
Stop();
@ -3205,8 +3187,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
steamParentalCode = await Logging.GetUserInput(ASF.EUserInputType.SteamParentalCode, BotName).ConfigureAwait(false);
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (string.IsNullOrEmpty(steamParentalCode) || !SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode!)) {
if (string.IsNullOrEmpty(steamParentalCode) || !SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(steamParentalCode)));
Stop();
@ -3458,8 +3439,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
break;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
CStore_RegisterCDKey_Response? response = await Actions.RedeemKey(key!).ConfigureAwait(false);
CStore_RegisterCDKey_Response? response = await Actions.RedeemKey(key).ConfigureAwait(false);
if (response == null) {
continue;
@ -3472,8 +3452,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
if ((purchaseResultDetail == EPurchaseResultDetail.CannotRedeemCodeFromClient) || ((purchaseResultDetail == EPurchaseResultDetail.BadActivationCode) && assumeWalletKeyOnBadActivationCode)) {
// If it's a wallet code, we try to redeem it first, then handle the inner result as our primary one
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
(EResult Result, EPurchaseResultDetail? PurchaseResult, string? BalanceText)? walletResult = await ArchiWebHandler.RedeemWalletKey(key!).ConfigureAwait(false);
(EResult Result, EPurchaseResultDetail? PurchaseResult, string? BalanceText)? walletResult = await ArchiWebHandler.RedeemWalletKey(key).ConfigureAwait(false);
if (walletResult != null) {
result = walletResult.Value.Result;
@ -3521,12 +3500,10 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
break;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
BotDatabase.RemoveGameToRedeemInBackground(key!);
BotDatabase.RemoveGameToRedeemInBackground(key);
// If user omitted the name or intentionally provided the same name as key, replace it with the Steam result
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (name!.Equals(key, StringComparison.OrdinalIgnoreCase) && (items?.Count > 0)) {
if (name.Equals(key, StringComparison.OrdinalIgnoreCase) && (items?.Count > 0)) {
name = string.Join(", ", items.Values);
}
@ -3813,7 +3790,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
BotDatabase.AccessToken = ArchiCryptoHelper.Encrypt(BotConfig.PasswordFormat, accessToken);
if (!string.IsNullOrEmpty(refreshToken)) {
BotDatabase.RefreshToken = ArchiCryptoHelper.Encrypt(BotConfig.PasswordFormat, refreshToken!);
BotDatabase.RefreshToken = ArchiCryptoHelper.Encrypt(BotConfig.PasswordFormat, refreshToken);
}
} else {
BotDatabase.AccessToken = accessToken;
@ -3856,8 +3833,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
if (!string.IsNullOrEmpty(steamParentalCode)) {
byte i = 0;
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
byte[] password = new byte[steamParentalCode!.Length];
byte[] password = new byte[steamParentalCode.Length];
foreach (char character in steamParentalCode.TakeWhile(static character => character is >= '0' and <= '9')) {
password[i++] = (byte) character;

View file

@ -470,8 +470,7 @@ public sealed class CardsFarmer : IAsyncDisposable, IDisposable {
continue;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
string[] appIDSplitted = appIDText!.Split('_');
string[] appIDSplitted = appIDText.Split('_');
if (appIDSplitted.Length < 5) {
Bot.ArchiLogger.LogNullError(appIDSplitted);

View file

@ -307,8 +307,7 @@ public sealed class ArchiWebHandler : IDisposable {
}
// Interpret the reason and see if we should try again
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
switch (response.Content!.ErrorCode) {
switch (response.Content.ErrorCode) {
case EResult.DuplicateRequest:
case EResult.ServiceUnavailable:
response = null;
@ -317,8 +316,7 @@ public sealed class ArchiWebHandler : IDisposable {
}
// This is actually client error with a reason, so it doesn't make sense to retry
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content!.ErrorText), null, response.StatusCode);
throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.ErrorText), null, response.StatusCode);
}
}
} finally {
@ -413,9 +411,7 @@ public sealed class ArchiWebHandler : IDisposable {
}
Dictionary<string, object?> arguments = new(2, StringComparer.Ordinal) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
{ "access_token", accessToken! },
{ "access_token", accessToken },
{ "steamid", Bot.SteamID }
};
@ -478,8 +474,7 @@ public sealed class ArchiWebHandler : IDisposable {
}
Dictionary<string, object?> arguments = new(StringComparer.Ordinal) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
{ "key", steamApiKey! }
{ "key", steamApiKey }
};
if (activeOnly.HasValue) {
@ -594,8 +589,7 @@ public sealed class ArchiWebHandler : IDisposable {
return null;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
parsedTags.Add(new Tag(identifier!, value));
parsedTags.Add(new Tag(identifier, value));
}
parsedDescription.Tags = parsedTags.ToImmutableHashSet();
@ -774,8 +768,7 @@ public sealed class ArchiWebHandler : IDisposable {
}
// This is actually client error with a reason, so it doesn't make sense to retry
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content!.ErrorText));
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.ErrorText));
return (false, tradeOfferIDs, mobileTradeOfferIDs);
}
@ -1116,11 +1109,9 @@ public sealed class ArchiWebHandler : IDisposable {
};
if (data != null) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
data[sessionName] = sessionID!;
data[sessionName] = sessionID;
} else {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
data = new Dictionary<string, string>(1, StringComparer.Ordinal) { { sessionName, sessionID! } };
data = new Dictionary<string, string>(1, StringComparer.Ordinal) { { sessionName, sessionID } };
}
}
@ -1228,11 +1219,9 @@ public sealed class ArchiWebHandler : IDisposable {
};
if (data != null) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
data[sessionName] = sessionID!;
data[sessionName] = sessionID;
} else {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
data = new Dictionary<string, string>(1, StringComparer.Ordinal) { { sessionName, sessionID! } };
data = new Dictionary<string, string>(1, StringComparer.Ordinal) { { sessionName, sessionID } };
}
}
@ -1339,8 +1328,7 @@ public sealed class ArchiWebHandler : IDisposable {
_ => throw new InvalidOperationException(nameof(session))
};
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
KeyValuePair<string, string> sessionValue = new(sessionName, sessionID!);
KeyValuePair<string, string> sessionValue = new(sessionName, sessionID);
if (data != null) {
data.Remove(sessionValue);
@ -1454,11 +1442,9 @@ public sealed class ArchiWebHandler : IDisposable {
};
if (data != null) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
data[sessionName] = sessionID!;
data[sessionName] = sessionID;
} else {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
data = new Dictionary<string, string>(1, StringComparer.Ordinal) { { sessionName, sessionID! } };
data = new Dictionary<string, string>(1, StringComparer.Ordinal) { { sessionName, sessionID } };
}
}
@ -1599,8 +1585,7 @@ public sealed class ArchiWebHandler : IDisposable {
}
// This is actually client error with a reason, so it doesn't make sense to retry
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content!.ErrorText));
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.ErrorText));
return (false, false);
}
@ -1846,15 +1831,12 @@ public sealed class ArchiWebHandler : IDisposable {
}
Dictionary<string, object?> arguments = new(!string.IsNullOrEmpty(tradeToken) ? 3 : 2, StringComparer.Ordinal) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
{ "key", steamApiKey! },
{ "key", steamApiKey },
{ "steamid_target", steamID }
};
if (!string.IsNullOrEmpty(tradeToken)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
arguments["trade_offer_access_token"] = tradeToken!;
arguments["trade_offer_access_token"] = tradeToken;
}
KeyValue? response = null;
@ -1954,8 +1936,7 @@ public sealed class ArchiWebHandler : IDisposable {
return null;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (giftCardIDText!.Length <= 13) {
if (giftCardIDText.Length <= 13) {
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(giftCardIDText)));
return null;
@ -2231,8 +2212,7 @@ public sealed class ArchiWebHandler : IDisposable {
// Unlock Steam Parental if needed
if (!string.IsNullOrEmpty(parentalCode)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!await UnlockParentalAccount(parentalCode!).ConfigureAwait(false)) {
if (!await UnlockParentalAccount(parentalCode).ConfigureAwait(false)) {
return false;
}
}
@ -2635,8 +2615,7 @@ public sealed class ArchiWebHandler : IDisposable {
ObjectResponse<AccessTokenResponse>? response = await UrlGetToJsonObjectWithSession<AccessTokenResponse>(request).ConfigureAwait(false);
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
return !string.IsNullOrEmpty(response?.Content?.Data.WebAPIToken) ? (true, response!.Content!.Data.WebAPIToken) : (false, null);
return !string.IsNullOrEmpty(response?.Content?.Data.WebAPIToken) ? (true, response.Content.Data.WebAPIToken) : (false, null);
}
private async Task<(bool Success, string? Result)> ResolveApiKey() {
@ -2711,9 +2690,7 @@ public sealed class ArchiWebHandler : IDisposable {
}
Dictionary<string, object?> arguments = new(2, StringComparer.Ordinal) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
{ "key", steamApiKey! },
{ "key", steamApiKey },
{ "steamids", Bot.SteamID }
};
@ -2815,9 +2792,7 @@ public sealed class ArchiWebHandler : IDisposable {
Dictionary<string, string> data = new(2, StringComparer.Ordinal) {
{ "pin", parentalCode },
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
{ "sessionid", sessionID! }
{ "sessionid", sessionID }
};
// This request doesn't go through UrlPostRetryWithSession as we have no access to session refresh capability (this is in fact session initialization)

View file

@ -47,8 +47,7 @@ internal static class SteamChatMessage {
if (!string.IsNullOrEmpty(steamMessagePrefix)) {
// We must escape our message prefix if needed
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
steamMessagePrefix = Escape(steamMessagePrefix!);
steamMessagePrefix = Escape(steamMessagePrefix);
prefixBytes = GetMessagePrefixBytes(steamMessagePrefix);

View file

@ -343,13 +343,11 @@ public sealed class Commands {
string? commandPrefix = ASF.GlobalConfig != null ? ASF.GlobalConfig.CommandPrefix : GlobalConfig.DefaultCommandPrefix;
if (!string.IsNullOrEmpty(commandPrefix)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!message.StartsWith(commandPrefix!, StringComparison.Ordinal)) {
if (!message.StartsWith(commandPrefix, StringComparison.Ordinal)) {
string? pluginsResponse = await PluginsCore.OnBotMessage(Bot, steamID, message).ConfigureAwait(false);
if (!string.IsNullOrEmpty(pluginsResponse)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!await Bot.SendMessage(steamID, pluginsResponse!).ConfigureAwait(false)) {
if (!await Bot.SendMessage(steamID, pluginsResponse).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(Bot.SendMessage)));
Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.Content, pluginsResponse));
}
@ -358,8 +356,7 @@ public sealed class Commands {
return;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (message.Length == commandPrefix!.Length) {
if (message.Length == commandPrefix.Length) {
// If the message starts with command prefix and is of the same length as command prefix, then it's just empty command trigger, useless
return;
}
@ -395,8 +392,7 @@ public sealed class Commands {
response = FormatBotResponse(Strings.ErrorAccessDenied);
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!await Bot.SendMessage(steamID, response!).ConfigureAwait(false)) {
if (!await Bot.SendMessage(steamID, response).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(Bot.SendMessage)));
Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.Content, response));
}
@ -415,13 +411,11 @@ public sealed class Commands {
string? commandPrefix = ASF.GlobalConfig != null ? ASF.GlobalConfig.CommandPrefix : GlobalConfig.DefaultCommandPrefix;
if (!string.IsNullOrEmpty(commandPrefix)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!message.StartsWith(commandPrefix!, StringComparison.Ordinal)) {
if (!message.StartsWith(commandPrefix, StringComparison.Ordinal)) {
string? pluginsResponse = await PluginsCore.OnBotMessage(Bot, steamID, message).ConfigureAwait(false);
if (!string.IsNullOrEmpty(pluginsResponse)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!await Bot.SendMessage(chatGroupID, chatID, pluginsResponse!).ConfigureAwait(false)) {
if (!await Bot.SendMessage(chatGroupID, chatID, pluginsResponse).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(Bot.SendMessage)));
Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.Content, pluginsResponse));
}
@ -430,8 +424,7 @@ public sealed class Commands {
return;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (message.Length == commandPrefix!.Length) {
if (message.Length == commandPrefix.Length) {
// If the message starts with command prefix and is of the same length as command prefix, then it's just empty command trigger, useless
return;
}
@ -469,8 +462,7 @@ public sealed class Commands {
response = FormatBotResponse(Strings.ErrorAccessDenied);
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!await Bot.SendMessage(chatGroupID, chatID, response!).ConfigureAwait(false)) {
if (!await Bot.SendMessage(chatGroupID, chatID, response).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(Bot.SendMessage)));
Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.Content, response));
}
@ -2304,8 +2296,7 @@ public sealed class Commands {
string? previousKey = key;
while (!string.IsNullOrEmpty(key)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
string startingKey = key!;
string startingKey = key;
using (IEnumerator<Bot> botsEnumerator = Bot.Bots.Where(bot => (bot.Value != Bot) && bot.Value.IsConnectedAndLoggedOn && ((access >= EAccess.Owner) || ((steamID != 0) && (bot.Value.GetAccess(steamID) >= EAccess.Operator)))).OrderByDescending(bot => Bot.BotsComparer?.Compare(bot.Key, Bot.BotName) > 0).ThenBy(static bot => bot.Key, Bot.BotsComparer).Select(static bot => bot.Value).GetEnumerator()) {
Bot? currentBot = Bot;
@ -2316,8 +2307,7 @@ public sealed class Commands {
previousKey = key;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (redeemFlags.HasFlag(ERedeemFlags.Validate) && !Utilities.IsValidCdKey(key!)) {
if (redeemFlags.HasFlag(ERedeemFlags.Validate) && !Utilities.IsValidCdKey(key)) {
// Next key
key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null;
@ -2336,8 +2326,7 @@ public sealed class Commands {
Dictionary<uint, string>? items = null;
if (!skipRequest) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
CStore_RegisterCDKey_Response? redeemResult = await currentBot.Actions.RedeemKey(key!).ConfigureAwait(false);
CStore_RegisterCDKey_Response? redeemResult = await currentBot.Actions.RedeemKey(key).ConfigureAwait(false);
if (redeemResult != null) {
result = (EResult) redeemResult.purchase_receipt_info.purchase_status;
@ -2364,8 +2353,7 @@ public sealed class Commands {
if ((purchaseResultDetail == EPurchaseResultDetail.CannotRedeemCodeFromClient) || ((purchaseResultDetail == EPurchaseResultDetail.BadActivationCode) && assumeWalletKeyOnBadActivationCode)) {
// If it's a wallet code, we try to redeem it first, then handle the inner result as our primary one
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
(EResult Result, EPurchaseResultDetail? PurchaseResult, string? BalanceText)? walletResult = await currentBot.ArchiWebHandler.RedeemWalletKey(key!).ConfigureAwait(false);
(EResult Result, EPurchaseResultDetail? PurchaseResult, string? BalanceText)? walletResult = await currentBot.ArchiWebHandler.RedeemWalletKey(key).ConfigureAwait(false);
if (walletResult != null) {
result = walletResult.Value.Result;
@ -2390,8 +2378,7 @@ public sealed class Commands {
case EPurchaseResultDetail.NoDetail: // OK
case EPurchaseResultDetail.Timeout:
if ((result != EResult.Timeout) && (purchaseResultDetail != EPurchaseResultDetail.Timeout)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
unusedKeys.Remove(key!);
unusedKeys.Remove(key);
}
// Next key
@ -2428,8 +2415,7 @@ public sealed class Commands {
bool alreadyHandled = false;
foreach (Bot innerBot in Bot.Bots.Where(bot => (bot.Value != currentBot) && (!redeemFlags.HasFlag(ERedeemFlags.SkipInitial) || (bot.Value != Bot)) && !triedBots.Contains(bot.Value) && !rateLimitedBots.Contains(bot.Value) && bot.Value.IsConnectedAndLoggedOn && ((access >= EAccess.Owner) || ((steamID != 0) && (bot.Value.GetAccess(steamID) >= EAccess.Operator))) && ((items.Count == 0) || items.Keys.Any(packageID => !bot.Value.OwnedPackageIDs.ContainsKey(packageID)))).OrderBy(static bot => bot.Key, Bot.BotsComparer).Select(static bot => bot.Value)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
CStore_RegisterCDKey_Response? redeemResponse = await innerBot.Actions.RedeemKey(key!).ConfigureAwait(false);
CStore_RegisterCDKey_Response? redeemResponse = await innerBot.Actions.RedeemKey(key).ConfigureAwait(false);
if (redeemResponse == null) {
response.AppendLine(FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotRedeem, key, $"{EResult.Timeout}/{EPurchaseResultDetail.Timeout}"), innerBot.BotName));
@ -2449,8 +2435,7 @@ public sealed class Commands {
// This key is already handled, as we either redeemed it or we're sure it's dupe/invalid
alreadyHandled = true;
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
unusedKeys.Remove(key!);
unusedKeys.Remove(key);
break;
case EPurchaseResultDetail.RateLimited:
@ -2488,8 +2473,7 @@ public sealed class Commands {
default:
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(purchaseResultDetail), purchaseResultDetail));
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
unusedKeys.Remove(key!);
unusedKeys.Remove(key);
// Next key
key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null;
@ -3165,8 +3149,7 @@ public sealed class Commands {
GlobalConfig.EUpdateChannel channel = ASF.GlobalConfig?.UpdateChannel ?? GlobalConfig.DefaultUpdateChannel;
if (!string.IsNullOrEmpty(channelText)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (!Enum.TryParse(channelText!, true, out channel) || (channel == GlobalConfig.EUpdateChannel.None)) {
if (!Enum.TryParse(channelText, true, out channel) || (channel == GlobalConfig.EUpdateChannel.None)) {
return FormatStaticResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(channelText)));
}
}

View file

@ -130,8 +130,7 @@ public sealed class MobileAuthenticator : IDisposable {
// Build the alphanumeric code
uint fullCode = BitConverter.ToUInt32(bytes, 0) & 0x7fffffff;
// ReSharper disable once BuiltInTypeReferenceStyleForMemberAccess - required for .NET Framework
return String.Create(
return string.Create(
CodeDigits, fullCode, static (buffer, state) => {
for (byte i = 0; i < CodeDigits; i++) {
buffer[i] = CodeCharacters[(byte) (state % CodeCharacters.Count)];
@ -170,8 +169,7 @@ public sealed class MobileAuthenticator : IDisposable {
return null;
}
// ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework
ConfirmationsResponse? response = await Bot.ArchiWebHandler.GetConfirmations(deviceID!, confirmationHash!, time).ConfigureAwait(false);
ConfirmationsResponse? response = await Bot.ArchiWebHandler.GetConfirmations(deviceID, confirmationHash, time).ConfigureAwait(false);
if (response?.Success != true) {
return null;
@ -253,10 +251,7 @@ public sealed class MobileAuthenticator : IDisposable {
return false;
}
// ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework
bool? result = await Bot.ArchiWebHandler.HandleConfirmations(deviceID!, confirmationHash!, time, confirmations, accept).ConfigureAwait(false);
// ReSharper restore RedundantSuppressNullableWarningExpression - required for .NET Framework
bool? result = await Bot.ArchiWebHandler.HandleConfirmations(deviceID, confirmationHash, time, confirmations, accept).ConfigureAwait(false);
if (!result.HasValue) {
// Request timed out
@ -272,10 +267,7 @@ public sealed class MobileAuthenticator : IDisposable {
// In this case, we'll accept all pending confirmations one-by-one, synchronously (as Steam can't handle them in parallel)
// We totally ignore actual result returned by those calls, abort only if request timed out
foreach (Confirmation confirmation in confirmations) {
// ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework
bool? confirmationResult = await Bot.ArchiWebHandler.HandleConfirmation(deviceID!, confirmationHash!, time, confirmation.ID, confirmation.Nonce, accept).ConfigureAwait(false);
// ReSharper restore RedundantSuppressNullableWarningExpression - required for .NET Framework
bool? confirmationResult = await Bot.ArchiWebHandler.HandleConfirmation(deviceID, confirmationHash, time, confirmation.ID, confirmation.Nonce, accept).ConfigureAwait(false);
if (!confirmationResult.HasValue) {
return false;
@ -338,8 +330,7 @@ public sealed class MobileAuthenticator : IDisposable {
byte bufferSize = 8;
if (!string.IsNullOrEmpty(tag)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
bufferSize += (byte) Math.Min(32, tag!.Length);
bufferSize += (byte) Math.Min(32, tag.Length);
}
byte[] timeArray = BitConverter.GetBytes(time);
@ -353,8 +344,7 @@ public sealed class MobileAuthenticator : IDisposable {
Array.Copy(timeArray, buffer, 8);
if (!string.IsNullOrEmpty(tag)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
Array.Copy(Encoding.UTF8.GetBytes(tag!), 0, buffer, 8, bufferSize - 8);
Array.Copy(Encoding.UTF8.GetBytes(tag), 0, buffer, 8, bufferSize - 8);
}
#pragma warning disable CA5350 // This is actually a fair warning, but there is nothing we can do about Steam using weak cryptographic algorithms

View file

@ -522,11 +522,11 @@ public sealed class BotConfig {
return (false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorConfigPropertyInvalid, nameof(SteamMasterClanID), SteamMasterClanID));
}
if (!string.IsNullOrEmpty(SteamParentalCode) && ((SteamParentalCode!.Length != SteamParentalCodeLength) || SteamParentalCode.Any(static character => character is < '0' or > '9'))) {
if (!string.IsNullOrEmpty(SteamParentalCode) && ((SteamParentalCode.Length != SteamParentalCodeLength) || SteamParentalCode.Any(static character => character is < '0' or > '9'))) {
return (false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorConfigPropertyInvalid, nameof(SteamParentalCode), SteamParentalCode));
}
if (!string.IsNullOrEmpty(SteamTradeToken) && (SteamTradeToken!.Length != SteamTradeTokenLength)) {
if (!string.IsNullOrEmpty(SteamTradeToken) && (SteamTradeToken.Length != SteamTradeTokenLength)) {
return (false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorConfigPropertyInvalid, nameof(SteamTradeToken), SteamTradeToken));
}
@ -557,7 +557,7 @@ public sealed class BotConfig {
return SteamPassword;
}
string? result = await ArchiCryptoHelper.Decrypt(PasswordFormat, SteamPassword!).ConfigureAwait(false);
string? result = await ArchiCryptoHelper.Decrypt(PasswordFormat, SteamPassword).ConfigureAwait(false);
if (string.IsNullOrEmpty(result)) {
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(SteamPassword)));
@ -604,8 +604,7 @@ public sealed class BotConfig {
if (!valid) {
if (!string.IsNullOrEmpty(errorMessage)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
ASF.ArchiLogger.LogGenericError(errorMessage!);
ASF.ArchiLogger.LogGenericError(errorMessage);
}
return (null, null);
@ -617,13 +616,12 @@ public sealed class BotConfig {
HashSet<string> disallowedValues = new(StringComparer.InvariantCultureIgnoreCase) { "account" };
if (!string.IsNullOrEmpty(botConfig.SteamLogin)) {
disallowedValues.Add(botConfig.SteamLogin!);
disallowedValues.Add(botConfig.SteamLogin);
}
Utilities.InBackground(
() => {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
(bool isWeak, string? reason) = Utilities.TestPasswordStrength(decryptedSteamPassword!, disallowedValues);
(bool isWeak, string? reason) = Utilities.TestPasswordStrength(decryptedSteamPassword, disallowedValues);
if (isWeak) {
if (string.IsNullOrEmpty(botName)) {

View file

@ -155,7 +155,7 @@ public sealed class GlobalConfig {
Uri uri;
try {
uri = new Uri(WebProxyText!);
uri = new Uri(WebProxyText);
} catch (UriFormatException e) {
ASF.ArchiLogger.LogGenericException(e);
@ -472,7 +472,7 @@ public sealed class GlobalConfig {
return (false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorConfigPropertyInvalid, nameof(OptimizationMode), OptimizationMode));
}
if (!string.IsNullOrEmpty(SteamMessagePrefix) && !SteamChatMessage.IsValidPrefix(SteamMessagePrefix!)) {
if (!string.IsNullOrEmpty(SteamMessagePrefix) && !SteamChatMessage.IsValidPrefix(SteamMessagePrefix)) {
return (false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorConfigPropertyInvalid, nameof(SteamMessagePrefix), SteamMessagePrefix));
}
@ -523,8 +523,7 @@ public sealed class GlobalConfig {
if (!valid) {
if (!string.IsNullOrEmpty(errorMessage)) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
ASF.ArchiLogger.LogGenericError(errorMessage!);
ASF.ArchiLogger.LogGenericError(errorMessage);
}
return (null, null);
@ -535,7 +534,7 @@ public sealed class GlobalConfig {
case ArchiCryptoHelper.EHashingMethod.PlainText when !string.IsNullOrEmpty(globalConfig.IPCPassword):
Utilities.InBackground(
() => {
(bool isWeak, string? reason) = Utilities.TestPasswordStrength(globalConfig.IPCPassword!, ForbiddenIPCPasswordPhrases);
(bool isWeak, string? reason) = Utilities.TestPasswordStrength(globalConfig.IPCPassword, ForbiddenIPCPasswordPhrases);
if (isWeak) {
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningWeakIPCPassword, reason));

View file

@ -125,8 +125,7 @@ internal static class GitHub {
return null;
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
result[versionText!] = dateTime.ToUniversalTime();
result[versionText] = dateTime.ToUniversalTime();
}
return result;
@ -270,7 +269,7 @@ internal static class GitHub {
return null;
}
return BackingChangelog = ExtractChangelogFromBody(MarkdownBody!);
return BackingChangelog = ExtractChangelogFromBody(MarkdownBody);
}
}

View file

@ -66,14 +66,9 @@ public sealed class WebBrowser : IDisposable {
HttpClientHandler = new HttpClientHandler {
AllowAutoRedirect = false, // This must be false if we want to handle custom redirection schemes such as "steammobile://"
#if NETFRAMEWORK || NETSTANDARD
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip,
#else
AutomaticDecompression = DecompressionMethods.All,
#endif
CookieContainer = CookieContainer
CookieContainer = CookieContainer,
MaxConnectionsPerServer = MaxConnections
};
if (webProxy != null) {
@ -86,14 +81,6 @@ public sealed class WebBrowser : IDisposable {
}
}
#if NETFRAMEWORK || NETSTANDARD
if (!RuntimeMadness.IsRunningOnMono) {
HttpClientHandler.MaxConnectionsPerServer = MaxConnections;
}
#else
HttpClientHandler.MaxConnectionsPerServer = MaxConnections;
#endif
HttpClient = GenerateDisposableHttpClient(extendedTimeout);
}
@ -107,9 +94,7 @@ public sealed class WebBrowser : IDisposable {
byte connectionTimeout = ASF.GlobalConfig?.ConnectionTimeout ?? GlobalConfig.DefaultConnectionTimeout;
HttpClient result = new(HttpClientHandler, false) {
#if !NETFRAMEWORK && !NETSTANDARD
DefaultRequestVersion = HttpVersion.Version30,
#endif
Timeout = TimeSpan.FromSeconds(extendedTimeout ? ExtendedTimeout : connectionTimeout)
};
@ -710,13 +695,7 @@ public sealed class WebBrowser : IDisposable {
ServicePointManager.Expect100Continue = false;
// Reuse ports if possible
#if NETFRAMEWORK || NETSTANDARD
if (!RuntimeMadness.IsRunningOnMono) {
ServicePointManager.ReusePort = true;
}
#else
ServicePointManager.ReusePort = true;
#endif
}
private async Task<HttpResponseMessage?> InternalGet(Uri request, IReadOnlyCollection<KeyValuePair<string, string>>? headers = null, Uri? referer = null, ERequestOptions requestOptions = ERequestOptions.None, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead) {
@ -745,9 +724,7 @@ public sealed class WebBrowser : IDisposable {
while (true) {
using (HttpRequestMessage requestMessage = new(httpMethod, request)) {
#if !NETFRAMEWORK && !NETSTANDARD
requestMessage.Version = HttpClient.DefaultRequestVersion;
#endif
if (headers != null) {
foreach ((string header, string value) in headers) {

View file

@ -35,7 +35,7 @@ internal static class WebBrowserUtilities {
// We're going to create compressed stream and copy original content to it
MemoryStream compressionOutput = new();
(Stream compressionInput, string contentEncoding) = GetBestSupportedCompressionMethod(compressionOutput);
BrotliStream compressionInput = new(compressionOutput, CompressionLevel.SmallestSize, true);
await using (compressionInput.ConfigureAwait(false)) {
await content.CopyToAsync(compressionInput).ConfigureAwait(false);
@ -51,18 +51,8 @@ internal static class WebBrowserUtilities {
}
// Inform the server that we're sending compressed data
result.Headers.ContentEncoding.Add(contentEncoding);
result.Headers.ContentEncoding.Add("br");
return result;
}
private static (Stream CompressionInput, string ContentEncoding) GetBestSupportedCompressionMethod(Stream output) {
ArgumentNullException.ThrowIfNull(output);
#if NETFRAMEWORK || NETSTANDARD
return (new GZipStream(output, CompressionLevel.Optimal, true), "gzip");
#else
return (new BrotliStream(output, CompressionLevel.SmallestSize, true), "br");
#endif
}
}

View file

@ -33,49 +33,6 @@
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
</PropertyGroup>
<PropertyGroup Condition="'$(OS)' == 'Windows_NT' OR '$(ASFNetFramework)' != ''">
<TargetFrameworks>$(TargetFrameworks);net481</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition="'$(ASFNetStandard)' != ''">
<TargetFrameworks>$(TargetFrameworks);netstandard2.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="JustArchiNET.Madness" />
<PackageReference Include="TA.System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray" />
<Using Include="JustArchiNET.Madness" />
<Using Include="JustArchiNET.Madness.ArgumentExceptionMadness.ArgumentException" Alias="ArgumentException" />
<Using Include="JustArchiNET.Madness.ArgumentNullExceptionMadness.ArgumentNullException" Alias="ArgumentNullException" />
<Using Include="JustArchiNET.Madness.ArgumentOutOfRangeExceptionMadness.ArgumentOutOfRangeException" Alias="ArgumentOutOfRangeException" />
<Using Include="JustArchiNET.Madness.ArrayMadness.Array" Alias="Array" />
<Using Include="JustArchiNET.Madness.CancellationTokenSourceMadness.CancellationTokenSource" Alias="CancellationTokenSource" />
<Using Include="JustArchiNET.Madness.ConvertMadness.Convert" Alias="Convert" />
<Using Include="JustArchiNET.Madness.DirectoryInfoMadness.DirectoryInfo" Alias="DirectoryInfo" />
<Using Include="JustArchiNET.Madness.DirectoryMadness.Directory" Alias="Directory" />
<Using Include="JustArchiNET.Madness.EnumMadness.Enum" Alias="Enum" />
<Using Include="JustArchiNET.Madness.EnvironmentMadness.Environment" Alias="Environment" />
<Using Include="JustArchiNET.Madness.FileInfoMadness.FileInfo" Alias="FileInfo" />
<Using Include="JustArchiNET.Madness.FileMadness.File" Alias="File" />
<Using Include="JustArchiNET.Madness.FileMadness.UnixFileMode" Alias="UnixFileMode" />
<Using Include="JustArchiNET.Madness.HashCodeMadness.HashCode" Alias="HashCode" />
<Using Include="JustArchiNET.Madness.HMACSHA1Madness.HMACSHA1" Alias="HMACSHA1" />
<Using Include="JustArchiNET.Madness.HttpRequestExceptionMadness.HttpRequestException" Alias="HttpRequestException" />
<Using Include="JustArchiNET.Madness.OperatingSystemMadness.OperatingSystem" Alias="OperatingSystem" />
<Using Include="JustArchiNET.Madness.PathMadness.Path" Alias="Path" />
<Using Include="JustArchiNET.Madness.QuicExceptionMadness.QuicException" Alias="QuicException" />
<Using Include="JustArchiNET.Madness.RandomMadness.Random" Alias="Random" />
<Using Include="JustArchiNET.Madness.SHA256Madness.SHA256" Alias="SHA256" />
<Using Include="JustArchiNET.Madness.SHA512Madness.SHA512" Alias="SHA512" />
<Using Include="JustArchiNET.Madness.StringMadness.String" Alias="String" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
<Using Include="JustArchiNET.Madness.NewtonsoftJsonMadness.JsonTextReader" Alias="JsonTextReader" />
<Using Include="JustArchiNET.Madness.NewtonsoftJsonMadness.JsonTextWriter" Alias="JsonTextWriter" />
</ItemGroup>
<PropertyGroup Condition="'$(ASFVariant)' != ''">
<DefineConstants>$(DefineConstants);ASF_VARIANT_$(ASFVariant.Replace('-', '_').ToUpperInvariant())</DefineConstants>
</PropertyGroup>

View file

@ -20,29 +20,7 @@
<PackageVersion Include="System.Composition.AttributedModel" Version="8.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
<PackageVersion Include="zxcvbn-core" Version="7.0.92" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'net481'">
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<PackageVersion Include="JustArchiNET.Madness" Version="3.17.0" />
<PackageVersion Include="Microsoft.AspNetCore.Cors" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.Diagnostics" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.HttpOverrides" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageVersion Include="Microsoft.AspNetCore.ResponseCaching" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="3.1.32" />
<PackageVersion Include="Microsoft.Extensions.Logging.Configuration" Version="3.1.32" />
<PackageVersion Include="TA.System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray" Version="1.0.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
<PackageVersion Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
</ItemGroup>
</Project>