diff --git a/Directory.Build.props b/Directory.Build.props
index 93cac457..eb93f374 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -22,8 +22,6 @@
true
false
true
- true
- true
@@ -36,6 +34,11 @@
35a561290d20de2f
+
+ $(MeziantouPolyfill_ExcludedPolyfills);M:System.OperatingSystem.
+ $(MeziantouPolyfill_ExcludedPolyfills);T:System.Net.Http.
+
+
$([System.IO.Path]::GetDirectoryName($(DOTNET_HOST_PATH)))
$(ProgramFiles)\dotnet
diff --git a/Directory.Build.targets b/Directory.Build.targets
index dc320ece..6db20806 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -59,12 +59,15 @@
$(DefineConstants);SUPPORTS_AUTHORIZATION_MIDDLEWARE
$(DefineConstants);SUPPORTS_BCL_ASYNC_ENUMERABLE
$(DefineConstants);SUPPORTS_BULK_DBSET_OPERATIONS
+ $(DefineConstants);SUPPORTS_CHUNK_LINQ_EXTENSION
$(DefineConstants);SUPPORTS_DBSET_VALUETASK_FINDASYNC
$(DefineConstants);SUPPORTS_ENDPOINT_ROUTING
$(DefineConstants);SUPPORTS_ENVIRONMENT_PROCESS_PATH
+ $(DefineConstants);SUPPORTS_HEXADECIMAL_STRING_CONVERSION
$(DefineConstants);SUPPORTS_HTTP_CLIENT_DEFAULT_REQUEST_VERSION
$(DefineConstants);SUPPORTS_HTTP_CLIENT_DEFAULT_REQUEST_VERSION_POLICY
$(DefineConstants);SUPPORTS_HTTP_CLIENT_RESILIENCE
+ $(DefineConstants);SUPPORTS_INT32_RANDOM_NUMBER_GENERATOR_METHODS
$(DefineConstants);SUPPORTS_MULTIPLE_VALUES_IN_QUERYHELPERS
$(DefineConstants);SUPPORTS_NAMED_PIPE_STATIC_FACTORY_WITH_ACL
$(DefineConstants);SUPPORTS_ONE_SHOT_HASHING_METHODS
@@ -73,6 +76,7 @@
$(DefineConstants);SUPPORTS_PEM_ENCODED_KEY_IMPORT
$(DefineConstants);SUPPORTS_REDIRECTION_ON_SIGN_IN
$(DefineConstants);SUPPORTS_TEXT_ELEMENT_ENUMERATOR
+ $(DefineConstants);SUPPORTS_VALUETASK_COMPLETED_TASK
$(DefineConstants);SUPPORTS_WINFORMS_TASK_DIALOG
$(DefineConstants);SUPPORTS_ZLIB_COMPRESSION
@@ -155,19 +159,6 @@
$(DefineConstants);SUPPORTS_WINDOWS_RUNTIME
-
-
-
- $(DefineConstants);FeatureRuntimeInformation
-
-
-
-
-
-
-
-
-
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 45eb5471..b38e6fba 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -20,39 +20,40 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
+
+
+
+
-
+
-
+
-
+
diff --git a/shared/OpenIddict.Extensions/OpenIddictHelpers.cs b/shared/OpenIddict.Extensions/OpenIddictHelpers.cs
index 7389ab07..3a7328c6 100644
--- a/shared/OpenIddict.Extensions/OpenIddictHelpers.cs
+++ b/shared/OpenIddict.Extensions/OpenIddictHelpers.cs
@@ -527,14 +527,33 @@ internal static class OpenIddictHelpers
///
public static byte[] ComputeSha256Hash(byte[] data)
{
- using var algorithm = GetAlgorithmFromConfig() switch
+ var algorithm = GetAlgorithmFromConfig() switch
{
SHA256 result => result,
null => null,
var result => throw new CryptographicException(SR.FormatID0351(result.GetType().FullName))
};
- return algorithm is not null ? algorithm.ComputeHash(data) : SHA256.HashData(data);
+ // If no custom algorithm was registered, use either the static/one-shot HashData() API
+ // on platforms that support it or create a default instance provided by the BCL.
+ if (algorithm is null)
+ {
+#if SUPPORTS_ONE_SHOT_HASHING_METHODS
+ return SHA256.HashData(data);
+#else
+ algorithm = SHA256.Create();
+#endif
+ }
+
+ try
+ {
+ return algorithm.ComputeHash(data);
+ }
+
+ finally
+ {
+ algorithm.Dispose();
+ }
[UnconditionalSuppressMessage("Trimming", "IL2026",
Justification = "The default implementation is always used when no custom algorithm was registered.")]
@@ -551,14 +570,33 @@ internal static class OpenIddictHelpers
///
public static byte[] ComputeSha384Hash(byte[] data)
{
- using var algorithm = GetAlgorithmFromConfig() switch
+ var algorithm = GetAlgorithmFromConfig() switch
{
SHA384 result => result,
null => null,
var result => throw new CryptographicException(SR.FormatID0351(result.GetType().FullName))
};
- return algorithm is not null ? algorithm.ComputeHash(data) : SHA384.HashData(data);
+ // If no custom algorithm was registered, use either the static/one-shot HashData() API
+ // on platforms that support it or create a default instance provided by the BCL.
+ if (algorithm is null)
+ {
+#if SUPPORTS_ONE_SHOT_HASHING_METHODS
+ return SHA384.HashData(data);
+#else
+ algorithm = SHA384.Create();
+#endif
+ }
+
+ try
+ {
+ return algorithm.ComputeHash(data);
+ }
+
+ finally
+ {
+ algorithm.Dispose();
+ }
[UnconditionalSuppressMessage("Trimming", "IL2026",
Justification = "The default implementation is always used when no custom algorithm was registered.")]
@@ -575,14 +613,33 @@ internal static class OpenIddictHelpers
///
public static byte[] ComputeSha512Hash(byte[] data)
{
- using var algorithm = GetAlgorithmFromConfig() switch
+ var algorithm = GetAlgorithmFromConfig() switch
{
SHA512 result => result,
null => null,
var result => throw new CryptographicException(SR.FormatID0351(result.GetType().FullName))
};
- return algorithm is not null ? algorithm.ComputeHash(data) : SHA512.HashData(data);
+ // If no custom algorithm was registered, use either the static/one-shot HashData() API
+ // on platforms that support it or create a default instance provided by the BCL.
+ if (algorithm is null)
+ {
+#if SUPPORTS_ONE_SHOT_HASHING_METHODS
+ return SHA512.HashData(data);
+#else
+ algorithm = SHA512.Create();
+#endif
+ }
+
+ try
+ {
+ return algorithm.ComputeHash(data);
+ }
+
+ finally
+ {
+ algorithm.Dispose();
+ }
[UnconditionalSuppressMessage("Trimming", "IL2026",
Justification = "The default implementation is always used when no custom algorithm was registered.")]
@@ -599,22 +656,46 @@ internal static class OpenIddictHelpers
///
public static byte[] CreateRandomArray(int size)
{
- using var algorithm = GetAlgorithmFromConfig() switch
+ var algorithm = GetAlgorithmFromConfig() switch
{
RandomNumberGenerator result => result,
null => null,
var result => throw new CryptographicException(SR.FormatID0351(result.GetType().FullName))
};
- if (algorithm is not null)
+ // If no custom random number generator was registered, use either the static GetBytes() or
+ // Fill() APIs on platforms that support them or create a default instance provided by the BCL.
+#if SUPPORTS_ONE_SHOT_RANDOM_NUMBER_GENERATOR_METHODS
+ if (algorithm is null)
{
var array = new byte[size / 8];
algorithm.GetBytes(array);
return array;
}
+#endif
+ var array = new byte[size / 8];
+
+#if SUPPORTS_STATIC_RANDOM_NUMBER_GENERATOR_METHODS
+ if (algorithm is null)
+ {
+ RandomNumberGenerator.Fill(array);
+ return array;
+ }
+#else
+ algorithm ??= RandomNumberGenerator.Create();
+#endif
+ try
+ {
+ algorithm.GetBytes(array);
+ }
- return RandomNumberGenerator.GetBytes(size / 8);
+ finally
+ {
+ algorithm.Dispose();
+ }
+
+ return array;
[UnconditionalSuppressMessage("Trimming", "IL2026",
Justification = "The default implementation is always used when no custom algorithm was registered.")]
@@ -633,30 +714,40 @@ internal static class OpenIddictHelpers
///
public static string CreateRandomString(ReadOnlySpan charset, int count)
{
- using var algorithm = GetAlgorithmFromConfig() switch
+ var algorithm = GetAlgorithmFromConfig() switch
{
RandomNumberGenerator result => result,
null => null,
var result => throw new CryptographicException(SR.FormatID0351(result.GetType().FullName))
};
- var builder = new StringBuilder();
-
- for (var index = 0; index < count; index++)
+ try
{
- // Pick a character in the specified charset by generating a random index.
- builder.Append(charset[index: algorithm switch
+ var builder = new StringBuilder();
+
+ for (var index = 0; index < count; index++)
{
- // If no custom random number generator was registered, use the static GetInt32() API.
- null => RandomNumberGenerator.GetInt32(0, charset.Length),
+ // Pick a character in the specified charset by generating a random index.
+ builder.Append(charset[index: algorithm switch
+ {
+#if SUPPORTS_INT32_RANDOM_NUMBER_GENERATOR_METHODS
+ // If no custom random number generator was registered, use
+ // the static GetInt32() API on platforms that support it.
+ null => RandomNumberGenerator.GetInt32(0, charset.Length),
+#endif
+ // Otherwise, create a default implementation if necessary
+ // and use the local function that achieves the same result.
+ _ => GetInt32(algorithm ??= RandomNumberGenerator.Create(), 0..charset.Length)
+ }]);
+ }
- // Otherwise, create a default implementation if necessary
- // and use the local function that achieves the same result.
- _ => GetInt32(algorithm, 0..charset.Length)
- }]);
+ return builder.ToString();
}
- return builder.ToString();
+ finally
+ {
+ algorithm?.Dispose();
+ }
static int GetInt32(RandomNumberGenerator algorithm, Range range)
{
diff --git a/shared/OpenIddict.Extensions/OpenIddictPolyfills.cs b/shared/OpenIddict.Extensions/OpenIddictPolyfills.cs
new file mode 100644
index 00000000..07f12b29
--- /dev/null
+++ b/shared/OpenIddict.Extensions/OpenIddictPolyfills.cs
@@ -0,0 +1,306 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ * See https://github.com/openiddict/openiddict-core for more information concerning
+ * the license and the contributors participating to this project.
+ */
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
+namespace OpenIddict.Extensions;
+
+///
+/// Exposes common polyfills used by the OpenIddict assemblies.
+///
+internal static class OpenIddictPolyfills
+{
+ extension(ArgumentOutOfRangeException)
+ {
+ /// Throws an if is negative.
+ /// The argument to validate as non-negative.
+ /// The name of the parameter with which corresponds.
+ public static void ThrowIfNegative(T value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
+ where T : struct, IComparable
+ {
+ switch (value)
+ {
+ case byte or ushort or uint or ulong or char:
+ return;
+ case sbyte n:
+ if (n < 0)
+ ThrowArgumentOutOfRangeException(paramName, value);
+ return;
+ case short n:
+ if (n < 0)
+ ThrowArgumentOutOfRangeException(paramName, value);
+ return;
+ case int n:
+ if (n < 0)
+ ThrowArgumentOutOfRangeException(paramName, value);
+ return;
+ case long n:
+ if (n < 0L)
+ ThrowArgumentOutOfRangeException(paramName, value);
+ return;
+
+ case float n:
+ if (n < 0F)
+ ThrowArgumentOutOfRangeException(paramName, value);
+ return;
+ case double n:
+ if (n < 0D)
+ ThrowArgumentOutOfRangeException(paramName, value);
+ return;
+ case decimal n:
+ if (n < 0M)
+ ThrowArgumentOutOfRangeException(paramName, value);
+ return;
+ default:
+ throw new InvalidOperationException($"Invalid type '{typeof(T).AssemblyQualifiedName}' for {paramName}.");
+ }
+
+ static void ThrowArgumentOutOfRangeException(string? paramName, object value)
+ {
+ throw new ArgumentOutOfRangeException(paramName, value, $"{paramName} ('{value}') must not be negative.");
+ }
+ }
+ }
+
+ extension(Convert)
+ {
+#if !SUPPORTS_HEXADECIMAL_STRING_CONVERSION
+
+ /// Converts the specified string, which encodes binary data as hex characters, to an equivalent 8-bit unsigned integer array.
+ /// The string to convert.
+ /// An array of 8-bit unsigned integers that is equivalent to .
+ /// is null.
+ /// The length of , is not zero or a multiple of 2.
+ /// The format of is invalid. contains a non-hex character.
+ public static byte[] FromHexString(string s)
+ {
+ if ((uint) s.Length % 2 is not 0)
+ {
+ throw new FormatException(SR.GetResourceString(SR.ID0413));
+ }
+
+ var array = new byte[s.Length / 2];
+
+ for (var index = 0; index < s.Length; index += 2)
+ {
+ array[index / 2] = Convert.ToByte(s.Substring(index, 2), 16);
+ }
+
+ return array;
+ }
+#endif
+ }
+
+ extension(IEnumerable source)
+ {
+#if !SUPPORTS_CHUNK_LINQ_EXTENSION
+ ///
+ /// Split the elements of a sequence into chunks of size at most .
+ ///
+ ///
+ /// Every chunk except the last will be of size .
+ /// The last chunk will contain the remaining elements and may be of a smaller size.
+ ///
+ /// Maximum size of each chunk.
+ ///
+ /// An that contains the elements of the input
+ /// sequence split into chunks of size .
+ ///
+ public IEnumerable Chunk(int size)
+ {
+ // Note: this polyfill was directly copied from .NET's source code:
+ // https://github.com/dotnet/runtime/blob/main/src/libraries/System.Linq/src/System/Linq/Chunk.cs.
+
+ using IEnumerator enumerator = source.GetEnumerator();
+
+ if (enumerator.MoveNext())
+ {
+ var count = Math.Min(size, 4);
+ int index;
+
+ do
+ {
+ var array = new TSource[count];
+
+ array[0] = enumerator.Current;
+ index = 1;
+
+ if (size != array.Length)
+ {
+ for (; index < size && enumerator.MoveNext(); index++)
+ {
+ if (index >= array.Length)
+ {
+ count = (int) Math.Min((uint) size, 2 * (uint) array.Length);
+ Array.Resize(ref array, count);
+ }
+
+ array[index] = enumerator.Current;
+ }
+ }
+
+ else
+ {
+ var local = array;
+ Debug.Assert(local.Length == size);
+ for (; (uint) index < (uint) local.Length && enumerator.MoveNext(); index++)
+ {
+ local[index] = enumerator.Current;
+ }
+ }
+
+ if (index != array.Length)
+ {
+ Array.Resize(ref array, index);
+ }
+
+ yield return array;
+ }
+
+ while (index >= size && enumerator.MoveNext());
+ }
+ }
+#endif
+ }
+
+ extension(OperatingSystem)
+ {
+#if !SUPPORTS_OPERATING_SYSTEM_VERSIONS_COMPARISON
+ ///
+ /// Indicates whether the current application is running on Android.
+ ///
+ public static bool IsAndroid() => RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID"));
+
+ ///
+ /// Check for the Android API level (returned by 'ro.build.version.sdk') with a >=
+ /// version comparison. Used to guard APIs that were added in the given Android release.
+ ///
+ public static bool IsAndroidVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0)
+ => IsAndroid() && IsOSVersionAtLeast(major, minor, build, revision);
+
+ ///
+ /// Indicates whether the current application is running on iOS or MacCatalyst.
+ ///
+ [SupportedOSPlatformGuard("maccatalyst")]
+ public static bool IsIOS() => RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS"));
+
+ ///
+ /// Check for the iOS/MacCatalyst version (returned by 'libobjc.get_operatingSystemVersion')
+ /// with a >= version comparison. Used to guard APIs that were added in the given iOS release.
+ ///
+ [SupportedOSPlatformGuard("maccatalyst")]
+ public static bool IsIOSVersionAtLeast(int major, int minor = 0, int build = 0)
+ => IsIOS() && IsOSVersionAtLeast(major, minor, build, 0);
+
+ ///
+ /// Indicates whether the current application is running on Linux.
+ ///
+ public static bool IsLinux() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
+
+ ///
+ /// Indicates whether the current application is running on Mac Catalyst.
+ ///
+ public static bool IsMacCatalyst() => RuntimeInformation.IsOSPlatform(OSPlatform.Create("MACCATALYST"));
+
+ ///
+ /// Check for the Mac Catalyst version (iOS version as presented in Apple documentation) with a >=
+ /// version comparison. Used to guard APIs that were added in the given Mac Catalyst release.
+ ///
+ public static bool IsMacCatalystVersionAtLeast(int major, int minor = 0, int build = 0)
+ => IsMacCatalyst() && IsOSVersionAtLeast(major, minor, build, 0);
+
+ ///
+ /// Indicates whether the current application is running on macOS.
+ ///
+ public static bool IsMacOS() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
+
+ ///
+ /// Check for the macOS version (returned by 'libobjc.get_operatingSystemVersion') with a >=
+ /// version comparison. Used to guard APIs that were added in the given macOS release.
+ ///
+ public static bool IsMacOSVersionAtLeast(int major, int minor = 0, int build = 0)
+ => IsMacOS() && IsOSVersionAtLeast(major, minor, build, 0);
+
+ ///
+ /// Indicates whether the current application is running on Windows.
+ ///
+ public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+
+ ///
+ /// Check for the Windows version (returned by 'RtlGetVersion') with a >= version
+ /// comparison. Used to guard APIs that were added in the given Windows release.
+ ///
+ public static bool IsWindowsVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0)
+ {
+ if (Environment.OSVersion.Platform is PlatformID.Win32NT &&
+ Environment.OSVersion.Version >= new Version(major, minor, build, revision))
+ {
+ return true;
+ }
+
+ // Note: on older versions of .NET, Environment.OSVersion.Version is known to be affected by
+ // the compatibility shims used by Windows 10+ when the application doesn't have a manifest
+ // that explicitly indicates it's compatible with Windows 10 and higher. To avoid that, a
+ // second pass using RuntimeInformation.OSDescription (that calls NtDll.RtlGetVersion() under
+ // the hood) is made. Note: no version is returned on UWP due to the missing Win32 API.
+ return RuntimeInformation.OSDescription.StartsWith("Microsoft Windows ", StringComparison.OrdinalIgnoreCase) &&
+ RuntimeInformation.OSDescription["Microsoft Windows ".Length..] is string value &&
+ Version.TryParse(value, out Version? version) && version >= new Version(major, minor, build, revision);
+ }
+#endif
+ }
+
+ extension(ValueTask)
+ {
+#if !SUPPORTS_VALUETASK_COMPLETED_TASK
+ ///
+ /// Gets a task that has already completed successfully.
+ ///
+ public static ValueTask CompletedTask => default;
+#endif
+ }
+
+ extension(ValueTask)
+ {
+#if !SUPPORTS_VALUETASK_COMPLETED_TASK
+ ///
+ /// Gets a task that has already completed successfully.
+ ///
+ public static ValueTask CompletedTask => default;
+#endif
+ }
+
+#if !SUPPORTS_OPERATING_SYSTEM_VERSIONS_COMPARISON
+ static bool IsOSVersionAtLeast(int major, int minor, int build, int revision)
+ {
+ Version current = Environment.OSVersion.Version;
+
+ if (current.Major != major)
+ {
+ return current.Major > major;
+ }
+ if (current.Minor != minor)
+ {
+ return current.Minor > minor;
+ }
+
+ int currentBuild = current.Build < 0 ? 0 : current.Build;
+ build = build < 0 ? 0 : build;
+ if (currentBuild != build)
+ {
+ return currentBuild > build;
+ }
+
+ int currentRevision = current.Revision < 0 ? 0 : current.Revision;
+ revision = revision < 0 ? 0 : revision;
+
+ return currentRevision >= revision;
+ }
+#endif
+}
diff --git a/src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj b/src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj
index a3cc3048..05fc3fd6 100644
--- a/src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj
+++ b/src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj
@@ -38,6 +38,11 @@
+
+
+
+
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddict.Client.SystemIntegration.csproj b/src/OpenIddict.Client.SystemIntegration/OpenIddict.Client.SystemIntegration.csproj
index 7c8cc5ca..1aa3a77d 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddict.Client.SystemIntegration.csproj
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddict.Client.SystemIntegration.csproj
@@ -30,7 +30,7 @@
allow loading dependencies that are not strong-named), the warning can be safely disabled.
-->
$(NoWarn);CS8002
- $(DefineConstants);FeatureRuntimeInformation;FeatureValueTuple
+ $(DefineConstants);FeatureValueTuple
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConfiguration.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConfiguration.cs
index ed274d2d..83c6fd8a 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConfiguration.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConfiguration.cs
@@ -62,12 +62,9 @@ public sealed class OpenIddictClientSystemIntegrationConfiguration : IConfigureO
ArgumentNullException.ThrowIfNull(options);
// Ensure the operating system version is supported.
- if ((OperatingSystem.IsAndroid() && !OperatingSystem.IsAndroidVersionAtLeast(21)) ||
- (OperatingSystem.IsIOS() && !OperatingSystem.IsIOSVersionAtLeast(12)) ||
- OperatingSystem.IsLinux() ||
- (OperatingSystem.IsMacCatalyst() && !OperatingSystem.IsMacCatalystVersionAtLeast(13, 1)) ||
- (OperatingSystem.IsMacOS() && !OperatingSystem.IsMacOSVersionAtLeast(10, 15)) ||
- (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(7)))
+ if (!OperatingSystem.IsAndroidVersionAtLeast(21) && !OperatingSystem.IsIOSVersionAtLeast(12) &&
+ !OperatingSystem.IsLinux() && !OperatingSystem.IsMacCatalystVersionAtLeast(13, 1) &&
+ !OperatingSystem.IsMacOSVersionAtLeast(10, 15) && !OperatingSystem.IsWindowsVersionAtLeast(7))
{
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0389));
}
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs
index 31f6d5c1..02a364bc 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs
@@ -28,12 +28,9 @@ public static class OpenIddictClientSystemIntegrationExtensions
ArgumentNullException.ThrowIfNull(builder);
// Ensure the operating system version is supported.
- if ((OperatingSystem.IsAndroid() && !OperatingSystem.IsAndroidVersionAtLeast(21)) ||
- (OperatingSystem.IsIOS() && !OperatingSystem.IsIOSVersionAtLeast(12)) ||
- OperatingSystem.IsLinux() ||
- (OperatingSystem.IsMacCatalyst() && !OperatingSystem.IsMacCatalystVersionAtLeast(13, 1)) ||
- (OperatingSystem.IsMacOS() && !OperatingSystem.IsMacOSVersionAtLeast(10, 15)) ||
- (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(7)))
+ if (!OperatingSystem.IsAndroidVersionAtLeast(21) && !OperatingSystem.IsIOSVersionAtLeast(12) &&
+ !OperatingSystem.IsLinux() && !OperatingSystem.IsMacCatalystVersionAtLeast(13, 1) &&
+ !OperatingSystem.IsMacOSVersionAtLeast(10, 15) && !OperatingSystem.IsWindowsVersionAtLeast(7))
{
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0389));
}
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
index 9ff291fe..079c8ee1 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
@@ -77,7 +77,7 @@ public static class OpenIddictClientSystemIntegrationHelpers
[SupportedOSPlatformGuard("maccatalyst13.1")]
[SupportedOSPlatformGuard("macos10.15")]
internal static bool IsASWebAuthenticationSessionSupported()
-#if SUPPORTS_AUTHENTICATION_SERVICES && SUPPORTS_OPERATING_SYSTEM_VERSIONS_COMPARISON
+#if SUPPORTS_AUTHENTICATION_SERVICES
=> OperatingSystem.IsIOSVersionAtLeast(12) ||
OperatingSystem.IsMacCatalystVersionAtLeast(13) ||
OperatingSystem.IsMacOSVersionAtLeast(10, 15);
@@ -92,7 +92,7 @@ public static class OpenIddictClientSystemIntegrationHelpers
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[SupportedOSPlatformGuard("android21.0")]
internal static bool IsCustomTabsIntentSupported()
-#if SUPPORTS_ANDROIDX_BROWSER && SUPPORTS_OPERATING_SYSTEM_VERSIONS_COMPARISON
+#if SUPPORTS_ANDROIDX_BROWSER
=> OperatingSystem.IsAndroidVersionAtLeast(21);
#else
=> false;
diff --git a/src/OpenIddict.Client.SystemNetHttp/OpenIddict.Client.SystemNetHttp.csproj b/src/OpenIddict.Client.SystemNetHttp/OpenIddict.Client.SystemNetHttp.csproj
index ea267002..968b12e7 100644
--- a/src/OpenIddict.Client.SystemNetHttp/OpenIddict.Client.SystemNetHttp.csproj
+++ b/src/OpenIddict.Client.SystemNetHttp/OpenIddict.Client.SystemNetHttp.csproj
@@ -6,7 +6,6 @@
$(NetCoreTargetFrameworks);
$(NetStandardTargetFrameworks)
- $(DefineConstants);FeatureRuntimeInformation
diff --git a/src/OpenIddict.Validation.SystemNetHttp/OpenIddict.Validation.SystemNetHttp.csproj b/src/OpenIddict.Validation.SystemNetHttp/OpenIddict.Validation.SystemNetHttp.csproj
index 5ed8891f..3b2fcfcb 100644
--- a/src/OpenIddict.Validation.SystemNetHttp/OpenIddict.Validation.SystemNetHttp.csproj
+++ b/src/OpenIddict.Validation.SystemNetHttp/OpenIddict.Validation.SystemNetHttp.csproj
@@ -6,7 +6,6 @@
$(NetCoreTargetFrameworks);
$(NetStandardTargetFrameworks)
- $(DefineConstants);FeatureRuntimeInformation