mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-16 14:30:31 +00:00
.NET 10 (#3482)
* Initial .NET 10 bump * Use KnownIPNetworks * .NET 10 library updates * First round of trimming fixes * Fix docker in .NET 10 * Resolve trimming warning * Bump packages to rc2
This commit is contained in:
committed by
GitHub
parent
245daec72e
commit
c8e8cd27b8
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -5,7 +5,7 @@ on: [push, pull_request]
|
|||||||
env:
|
env:
|
||||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||||
DOTNET_NOLOGO: true
|
DOTNET_NOLOGO: true
|
||||||
DOTNET_SDK_VERSION: 9.0
|
DOTNET_SDK_VERSION: 10.0
|
||||||
|
|
||||||
permissions: {}
|
permissions: {}
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/publish.yml
vendored
2
.github/workflows/publish.yml
vendored
@@ -6,7 +6,7 @@ env:
|
|||||||
CONFIGURATION: Release
|
CONFIGURATION: Release
|
||||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||||
DOTNET_NOLOGO: true
|
DOTNET_NOLOGO: true
|
||||||
DOTNET_SDK_VERSION: 9.0
|
DOTNET_SDK_VERSION: 10.0
|
||||||
NODE_JS_VERSION: 'lts/*'
|
NODE_JS_VERSION: 'lts/*'
|
||||||
PLUGINS_BUNDLED: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.MobileAuthenticator ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
|
PLUGINS_BUNDLED: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.MobileAuthenticator ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
|
||||||
PLUGINS_INCLUDED: ArchiSteamFarm.OfficialPlugins.Monitoring # Apart from declaring them here, there is certain amount of hardcoding needed below for uploading
|
PLUGINS_INCLUDED: ArchiSteamFarm.OfficialPlugins.Monitoring # Apart from declaring them here, there is certain amount of hardcoding needed below for uploading
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
|
||||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
|
||||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AngleSharp" IncludeAssets="compile" />
|
<PackageReference Include="AngleSharp" IncludeAssets="compile" />
|
||||||
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
|
||||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
|
||||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||||
<PackageReference Include="System.Linq.Async" IncludeAssets="compile" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
|
||||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
|
||||||
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" />
|
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" />
|
||||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
<PackageReference Include="JetBrains.Annotations.Sources" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
|
||||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
<PackageReference Include="Scalar.AspNetCore" />
|
<PackageReference Include="Scalar.AspNetCore" />
|
||||||
<PackageReference Include="SteamKit2" />
|
<PackageReference Include="SteamKit2" />
|
||||||
<PackageReference Include="System.Composition" />
|
<PackageReference Include="System.Composition" />
|
||||||
<PackageReference Include="System.Linq.Async" />
|
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ public static class Utilities {
|
|||||||
// Now extract the zip file to entirely new location, this decreases chance of corruptions if user kills the process during this stage
|
// Now extract the zip file to entirely new location, this decreases chance of corruptions if user kills the process during this stage
|
||||||
string updateDirectory = Path.Combine(targetDirectory, SharedInfo.UpdateDirectoryNew);
|
string updateDirectory = Path.Combine(targetDirectory, SharedInfo.UpdateDirectoryNew);
|
||||||
|
|
||||||
zipArchive.ExtractToDirectory(updateDirectory, true);
|
await zipArchive.ExtractToDirectoryAsync(updateDirectory, true).ConfigureAwait(false);
|
||||||
|
|
||||||
// Now, critical section begins, we're going to move all files from target directory to a backup directory
|
// Now, critical section begins, we're going to move all files from target directory to a backup directory
|
||||||
string backupDirectory = Path.Combine(targetDirectory, SharedInfo.UpdateDirectoryOld);
|
string backupDirectory = Path.Combine(targetDirectory, SharedInfo.UpdateDirectoryOld);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using NLog.Web;
|
using NLog.Web;
|
||||||
using Scalar.AspNetCore;
|
using Scalar.AspNetCore;
|
||||||
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
using IPNetwork = System.Net.IPNetwork;
|
||||||
|
|
||||||
namespace ArchiSteamFarm.IPC;
|
namespace ArchiSteamFarm.IPC;
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ internal static class ArchiKestrel {
|
|||||||
|
|
||||||
if (knownNetworks != null) {
|
if (knownNetworks != null) {
|
||||||
foreach (IPNetwork knownNetwork in knownNetworks) {
|
foreach (IPNetwork knownNetwork in knownNetworks) {
|
||||||
options.KnownNetworks.Add(knownNetwork);
|
options.KnownIPNetworks.Add(knownNetwork);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,19 +124,19 @@ internal sealed class ApiAuthenticationMiddleware {
|
|||||||
return (HttpStatusCode.OK, true);
|
return (HttpStatusCode.OK, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ForwardedHeadersOptions.KnownNetworks.Count == 0) {
|
if (ForwardedHeadersOptions.KnownIPNetworks.Count == 0) {
|
||||||
return (HttpStatusCode.Forbidden, true);
|
return (HttpStatusCode.Forbidden, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientIP.IsIPv4MappedToIPv6) {
|
if (clientIP.IsIPv4MappedToIPv6) {
|
||||||
IPAddress mappedClientIP = clientIP.MapToIPv4();
|
IPAddress mappedClientIP = clientIP.MapToIPv4();
|
||||||
|
|
||||||
if (ForwardedHeadersOptions.KnownNetworks.Any(network => network.Contains(mappedClientIP))) {
|
if (ForwardedHeadersOptions.KnownIPNetworks.Any(network => network.Contains(mappedClientIP))) {
|
||||||
return (HttpStatusCode.OK, true);
|
return (HttpStatusCode.OK, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ForwardedHeadersOptions.KnownNetworks.Any(network => network.Contains(clientIP)) ? HttpStatusCode.OK : HttpStatusCode.Forbidden, true);
|
return (ForwardedHeadersOptions.KnownIPNetworks.Any(network => network.Contains(clientIP)) ? HttpStatusCode.OK : HttpStatusCode.Forbidden, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.Request.Headers.TryGetValue(HeadersField, out StringValues passwords) && !context.Request.Query.TryGetValue("password", out passwords)) {
|
if (!context.Request.Headers.TryGetValue(HeadersField, out StringValues passwords) && !context.Request.Query.TryGetValue("password", out passwords)) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi;
|
||||||
|
|
||||||
namespace ArchiSteamFarm.IPC.Integration;
|
namespace ArchiSteamFarm.IPC.Integration;
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi;
|
||||||
|
|
||||||
namespace ArchiSteamFarm.IPC.Integration;
|
namespace ArchiSteamFarm.IPC.Integration;
|
||||||
|
|
||||||
@@ -45,16 +46,16 @@ public sealed class SwaggerItemsMinMaxAttribute : CustomSwaggerAttribute {
|
|||||||
public override void Apply(OpenApiSchema schema) {
|
public override void Apply(OpenApiSchema schema) {
|
||||||
ArgumentNullException.ThrowIfNull(schema);
|
ArgumentNullException.ThrowIfNull(schema);
|
||||||
|
|
||||||
if (schema.Items == null) {
|
if (schema.Items is not OpenApiSchema items) {
|
||||||
throw new InvalidOperationException(nameof(schema.Items));
|
throw new InvalidOperationException(nameof(schema.Items));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BackingMinimum.HasValue) {
|
if (BackingMinimum.HasValue) {
|
||||||
schema.Items.Minimum = BackingMinimum.Value;
|
items.Minimum = BackingMinimum.Value.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BackingMaximum.HasValue) {
|
if (BackingMaximum.HasValue) {
|
||||||
schema.Items.Maximum = BackingMaximum.Value;
|
items.Maximum = BackingMaximum.Value.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.OpenApi.Any;
|
using Microsoft.OpenApi;
|
||||||
using Microsoft.OpenApi.Extensions;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
|
|
||||||
namespace ArchiSteamFarm.IPC.Integration;
|
namespace ArchiSteamFarm.IPC.Integration;
|
||||||
|
|
||||||
@@ -36,10 +35,20 @@ public sealed class SwaggerSecurityCriticalAttribute : CustomSwaggerAttribute {
|
|||||||
public override void Apply(OpenApiSchema schema) {
|
public override void Apply(OpenApiSchema schema) {
|
||||||
ArgumentNullException.ThrowIfNull(schema);
|
ArgumentNullException.ThrowIfNull(schema);
|
||||||
|
|
||||||
if (schema.Items is { Reference: null }) {
|
JsonValue value = JsonValue.Create(true);
|
||||||
schema.Items.AddExtension(ExtensionName, new OpenApiBoolean(true));
|
|
||||||
|
if (schema.Items != null) {
|
||||||
|
if (schema.Items is OpenApiSchema items) {
|
||||||
|
items.AddExtension(ExtensionName, new JsonNodeExtension(value));
|
||||||
|
} else if (schema.Items.Extensions != null) {
|
||||||
|
schema.Items.Extensions[ExtensionName] = new JsonNodeExtension(value);
|
||||||
} else {
|
} else {
|
||||||
schema.AddExtension(ExtensionName, new OpenApiBoolean(true));
|
throw new InvalidOperationException(nameof(schema.Items));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
schema.AddExtension(ExtensionName, new JsonNodeExtension(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi;
|
||||||
using SteamKit2;
|
using SteamKit2;
|
||||||
|
|
||||||
namespace ArchiSteamFarm.IPC.Integration;
|
namespace ArchiSteamFarm.IPC.Integration;
|
||||||
@@ -38,7 +39,7 @@ public sealed class SwaggerSteamIdentifierAttribute : CustomSwaggerAttribute {
|
|||||||
public override void Apply(OpenApiSchema schema) {
|
public override void Apply(OpenApiSchema schema) {
|
||||||
ArgumentNullException.ThrowIfNull(schema);
|
ArgumentNullException.ThrowIfNull(schema);
|
||||||
|
|
||||||
schema.Minimum = new SteamID(MinimumAccountID, Universe, AccountType);
|
schema.Minimum = new SteamID(MinimumAccountID, Universe, AccountType).ConvertToUInt64().ToString(CultureInfo.InvariantCulture);
|
||||||
schema.Maximum = new SteamID(MaximumAccountID, Universe, AccountType);
|
schema.Maximum = new SteamID(MaximumAccountID, Universe, AccountType).ConvertToUInt64().ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,36 +22,50 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.OpenApi.Any;
|
using Microsoft.OpenApi;
|
||||||
using Microsoft.OpenApi.Extensions;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
|
|
||||||
namespace ArchiSteamFarm.IPC.Integration;
|
namespace ArchiSteamFarm.IPC.Integration;
|
||||||
|
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public sealed class SwaggerValidValuesAttribute : CustomSwaggerAttribute {
|
public sealed class SwaggerValidValuesAttribute : CustomSwaggerAttribute {
|
||||||
|
private const string ExtensionName = "x-valid-values";
|
||||||
|
|
||||||
public int[]? ValidIntValues { get; init; }
|
public int[]? ValidIntValues { get; init; }
|
||||||
public string[]? ValidStringValues { get; init; }
|
public string[]? ValidStringValues { get; init; }
|
||||||
|
|
||||||
|
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "We're not creating json values with non-primitive types")]
|
||||||
public override void Apply(OpenApiSchema schema) {
|
public override void Apply(OpenApiSchema schema) {
|
||||||
ArgumentNullException.ThrowIfNull(schema);
|
ArgumentNullException.ThrowIfNull(schema);
|
||||||
|
|
||||||
OpenApiArray validValues = [];
|
JsonArray validValues = [];
|
||||||
|
|
||||||
if (ValidIntValues != null) {
|
if (ValidIntValues != null) {
|
||||||
validValues.AddRange(ValidIntValues.Select(static type => new OpenApiInteger(type)));
|
foreach (int value in ValidIntValues) {
|
||||||
|
validValues.Add(JsonValue.Create(value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ValidStringValues != null) {
|
if (ValidStringValues != null) {
|
||||||
validValues.AddRange(ValidStringValues.Select(static type => new OpenApiString(type)));
|
foreach (string value in ValidStringValues) {
|
||||||
|
validValues.Add(JsonValue.Create(value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.Items is { Reference: null }) {
|
if (schema.Items != null) {
|
||||||
schema.Items.AddExtension("x-valid-values", validValues);
|
if (schema.Items is OpenApiSchema items) {
|
||||||
|
items.AddExtension(ExtensionName, new JsonNodeExtension(validValues));
|
||||||
|
} else if (schema.Items.Extensions != null) {
|
||||||
|
schema.Items.Extensions[ExtensionName] = new JsonNodeExtension(validValues);
|
||||||
} else {
|
} else {
|
||||||
schema.AddExtension("x-valid-values", validValues);
|
throw new InvalidOperationException(nameof(schema.Items));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
schema.AddExtension(ExtensionName, new JsonNodeExtension(validValues));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ using ArchiSteamFarm.IPC.Integration;
|
|||||||
using ArchiSteamFarm.Storage;
|
using ArchiSteamFarm.Storage;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.AspNetCore.OpenApi;
|
using Microsoft.AspNetCore.OpenApi;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi;
|
||||||
|
|
||||||
namespace ArchiSteamFarm.IPC.OpenApi;
|
namespace ArchiSteamFarm.IPC.OpenApi;
|
||||||
|
|
||||||
@@ -40,7 +40,6 @@ internal sealed class DocumentTransformer : IOpenApiDocumentTransformer {
|
|||||||
ArgumentNullException.ThrowIfNull(document);
|
ArgumentNullException.ThrowIfNull(document);
|
||||||
ArgumentNullException.ThrowIfNull(context);
|
ArgumentNullException.ThrowIfNull(context);
|
||||||
|
|
||||||
document.Info ??= new OpenApiInfo();
|
|
||||||
document.Info.Title = $"{SharedInfo.AssemblyName} API";
|
document.Info.Title = $"{SharedInfo.AssemblyName} API";
|
||||||
document.Info.Version = SharedInfo.Version.ToString();
|
document.Info.Version = SharedInfo.Version.ToString();
|
||||||
|
|
||||||
@@ -53,7 +52,7 @@ internal sealed class DocumentTransformer : IOpenApiDocumentTransformer {
|
|||||||
document.Info.License.Url = new Uri(SharedInfo.LicenseURL);
|
document.Info.License.Url = new Uri(SharedInfo.LicenseURL);
|
||||||
|
|
||||||
document.Components ??= new OpenApiComponents();
|
document.Components ??= new OpenApiComponents();
|
||||||
document.Components.SecuritySchemes ??= new Dictionary<string, OpenApiSecurityScheme>(1);
|
document.Components.SecuritySchemes ??= new Dictionary<string, IOpenApiSecurityScheme>(1);
|
||||||
|
|
||||||
document.Components.SecuritySchemes.Add(
|
document.Components.SecuritySchemes.Add(
|
||||||
nameof(GlobalConfig.IPCPassword), new OpenApiSecurityScheme {
|
nameof(GlobalConfig.IPCPassword), new OpenApiSecurityScheme {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ using System.Threading.Tasks;
|
|||||||
using ArchiSteamFarm.Storage;
|
using ArchiSteamFarm.Storage;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.AspNetCore.OpenApi;
|
using Microsoft.AspNetCore.OpenApi;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi;
|
||||||
|
|
||||||
namespace ArchiSteamFarm.IPC.OpenApi;
|
namespace ArchiSteamFarm.IPC.OpenApi;
|
||||||
|
|
||||||
@@ -45,13 +45,7 @@ internal sealed class OperationTransformer : IOpenApiOperationTransformer {
|
|||||||
operation.Security.Add(
|
operation.Security.Add(
|
||||||
new OpenApiSecurityRequirement {
|
new OpenApiSecurityRequirement {
|
||||||
{
|
{
|
||||||
new OpenApiSecurityScheme {
|
new OpenApiSecuritySchemeReference(nameof(GlobalConfig.IPCPassword), context.Document),
|
||||||
Reference = new OpenApiReference {
|
|
||||||
Id = nameof(GlobalConfig.IPCPassword),
|
|
||||||
Type = ReferenceType.SecurityScheme
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
[]
|
[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,14 +23,13 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ArchiSteamFarm.IPC.Integration;
|
using ArchiSteamFarm.IPC.Integration;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.AspNetCore.OpenApi;
|
using Microsoft.AspNetCore.OpenApi;
|
||||||
using Microsoft.OpenApi.Any;
|
using Microsoft.OpenApi;
|
||||||
using Microsoft.OpenApi.Extensions;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
|
|
||||||
namespace ArchiSteamFarm.IPC.OpenApi;
|
namespace ArchiSteamFarm.IPC.OpenApi;
|
||||||
|
|
||||||
@@ -72,9 +71,9 @@ internal sealed class SchemaTransformer : IOpenApiSchemaTransformer {
|
|||||||
schema.Format = "flags";
|
schema.Format = "flags";
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenApiObject definition = new();
|
JsonObject definition = new();
|
||||||
|
|
||||||
foreach (object? enumValue in context.JsonTypeInfo.Type.GetEnumValues()) {
|
foreach (object? enumValue in context.JsonTypeInfo.Type.GetEnumValuesAsUnderlyingType()) {
|
||||||
if (enumValue == null) {
|
if (enumValue == null) {
|
||||||
throw new InvalidOperationException(nameof(enumValue));
|
throw new InvalidOperationException(nameof(enumValue));
|
||||||
}
|
}
|
||||||
@@ -95,41 +94,26 @@ internal sealed class SchemaTransformer : IOpenApiSchemaTransformer {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
IOpenApiAny enumObject;
|
// OpenApi seems to support only int and long from underlying enum types: https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/integral-numeric-types
|
||||||
|
definition[enumName] = enumValue switch {
|
||||||
if (TryCast(enumValue, out int intValue)) {
|
sbyte value => JsonValue.Create((int) value),
|
||||||
enumObject = new OpenApiInteger(intValue);
|
byte value => JsonValue.Create((int) value),
|
||||||
} else if (TryCast(enumValue, out long longValue)) {
|
short value => JsonValue.Create((int) value),
|
||||||
enumObject = new OpenApiLong(longValue);
|
ushort value => JsonValue.Create((int) value),
|
||||||
} else if (TryCast(enumValue, out ulong ulongValue)) {
|
int value => JsonValue.Create(value),
|
||||||
// OpenApi spec doesn't support ulongs as of now
|
uint value => JsonValue.Create((long) value),
|
||||||
enumObject = new OpenApiString(ulongValue.ToString(CultureInfo.InvariantCulture));
|
long value => JsonValue.Create(value),
|
||||||
} else {
|
ulong value => JsonValue.Create(value.ToString(CultureInfo.InvariantCulture)),
|
||||||
throw new InvalidOperationException(nameof(enumValue));
|
nint value when nint.Size <= 4 => JsonValue.Create((int) value),
|
||||||
|
nint value when nint.Size <= 8 => JsonValue.Create((long) value),
|
||||||
|
nint value => JsonValue.Create(value.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
nuint value when nuint.Size <= 4 => JsonValue.Create((long) value),
|
||||||
|
nuint value => JsonValue.Create(value.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
_ => throw new InvalidOperationException(nameof(enumValue))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
definition.Add(enumName, enumObject);
|
schema.AddExtension("x-definition", new JsonNodeExtension(definition));
|
||||||
}
|
|
||||||
|
|
||||||
schema.AddExtension("x-definition", definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryCast<T>(object value, out T typedValue) where T : struct {
|
|
||||||
ArgumentNullException.ThrowIfNull(value);
|
|
||||||
|
|
||||||
try {
|
|
||||||
typedValue = (T) Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (InvalidCastException) {
|
|
||||||
typedValue = default(T);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} catch (OverflowException) {
|
|
||||||
typedValue = default(T);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1812 // False positive, the class is used internally
|
#pragma warning restore CA1812 // False positive, the class is used internally
|
||||||
|
|||||||
@@ -64,11 +64,11 @@ done
|
|||||||
|
|
||||||
BINARY_PREFIX=""
|
BINARY_PREFIX=""
|
||||||
|
|
||||||
if [ -n "${ASF_USER-}" ] && [ "$(id -u)" -eq 0 ] && id -u "$ASF_USER" >/dev/null 2>&1 && [ "$(id -u "$ASF_USER")" -gt 0 ]; then
|
if [ -n "${ASF_UID-}" ] && [ "$(id -u)" -eq 0 ] && id -u "$ASF_UID" >/dev/null 2>&1 && [ "$(id -u "$ASF_UID")" -gt 0 ]; then
|
||||||
# Fix permissions first to ensure ASF has read/write access to the directory specified by --path and its own
|
# Fix permissions first to ensure ASF has read/write access to the directory specified by --path and its own
|
||||||
chown -hR "${ASF_USER}:${ASF_USER}" . "$SCRIPT_DIR" || true
|
chown -hR "${ASF_UID}:${ASF_UID}" . "$SCRIPT_DIR" || true
|
||||||
|
|
||||||
BINARY_PREFIX="su ${ASF_USER} -c"
|
BINARY_PREFIX="su $(id -nu "$ASF_UID") -c"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
||||||
|
|||||||
@@ -64,11 +64,11 @@ done
|
|||||||
|
|
||||||
BINARY_PREFIX=""
|
BINARY_PREFIX=""
|
||||||
|
|
||||||
if [ -n "${ASF_USER-}" ] && [ "$(id -u)" -eq 0 ] && id -u "$ASF_USER" >/dev/null 2>&1 && [ "$(id -u "$ASF_USER")" -gt 0 ]; then
|
if [ -n "${ASF_UID-}" ] && [ "$(id -u)" -eq 0 ] && id -u "$ASF_UID" >/dev/null 2>&1 && [ "$(id -u "$ASF_UID")" -gt 0 ]; then
|
||||||
# Fix permissions first to ensure ASF has read/write access to the directory specified by --path and its own
|
# Fix permissions first to ensure ASF has read/write access to the directory specified by --path and its own
|
||||||
chown -hR "${ASF_USER}:${ASF_USER}" . "$SCRIPT_DIR" || true
|
chown -hR "${ASF_UID}:${ASF_UID}" . "$SCRIPT_DIR" || true
|
||||||
|
|
||||||
BINARY_PREFIX="su ${ASF_USER} -c"
|
BINARY_PREFIX="su $(id -nu "$ASF_UID") -c"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
||||||
|
|||||||
@@ -64,11 +64,11 @@ done
|
|||||||
|
|
||||||
BINARY_PREFIX=""
|
BINARY_PREFIX=""
|
||||||
|
|
||||||
if [ -n "${ASF_USER-}" ] && [ "$(id -u)" -eq 0 ] && id -u "$ASF_USER" >/dev/null 2>&1 && [ "$(id -u "$ASF_USER")" -gt 0 ]; then
|
if [ -n "${ASF_UID-}" ] && [ "$(id -u)" -eq 0 ] && id -u "$ASF_UID" >/dev/null 2>&1 && [ "$(id -u "$ASF_UID")" -gt 0 ]; then
|
||||||
# Fix permissions first to ensure ASF has read/write access to the directory specified by --path and its own
|
# Fix permissions first to ensure ASF has read/write access to the directory specified by --path and its own
|
||||||
chown -hR "${ASF_USER}:${ASF_USER}" . "$SCRIPT_DIR" || true
|
chown -hR "${ASF_UID}:${ASF_UID}" . "$SCRIPT_DIR" || true
|
||||||
|
|
||||||
BINARY_PREFIX="su ${ASF_USER} -c"
|
BINARY_PREFIX="su $(id -nu "$ASF_UID") -c"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
||||||
|
|||||||
@@ -64,11 +64,11 @@ done
|
|||||||
|
|
||||||
BINARY_PREFIX=""
|
BINARY_PREFIX=""
|
||||||
|
|
||||||
if [ -n "${ASF_USER-}" ] && [ "$(id -u)" -eq 0 ] && id -u "$ASF_USER" >/dev/null 2>&1 && [ "$(id -u "$ASF_USER")" -gt 0 ]; then
|
if [ -n "${ASF_UID-}" ] && [ "$(id -u)" -eq 0 ] && id -u "$ASF_UID" >/dev/null 2>&1 && [ "$(id -u "$ASF_UID")" -gt 0 ]; then
|
||||||
# Fix permissions first to ensure ASF has read/write access to the directory specified by --path and its own
|
# Fix permissions first to ensure ASF has read/write access to the directory specified by --path and its own
|
||||||
chown -hR "${ASF_USER}:${ASF_USER}" . "$SCRIPT_DIR" || true
|
chown -hR "${ASF_UID}:${ASF_UID}" . "$SCRIPT_DIR" || true
|
||||||
|
|
||||||
BINARY_PREFIX="su ${ASF_USER} -c"
|
BINARY_PREFIX="su $(id -nu "$ASF_UID") -c"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
CONFIG_PATH="$(pwd)/${CONFIG_PATH}"
|
||||||
|
|||||||
@@ -32,11 +32,8 @@
|
|||||||
<RepositoryUrl>$(PackageProjectUrl).git</RepositoryUrl>
|
<RepositoryUrl>$(PackageProjectUrl).git</RepositoryUrl>
|
||||||
<RollForward>LatestMajor</RollForward>
|
<RollForward>LatestMajor</RollForward>
|
||||||
<RuntimeIdentifiers>linux-arm;linux-arm64;linux-x64;osx-arm64;osx-x64;win-arm64;win-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>linux-arm;linux-arm64;linux-x64;osx-arm64;osx-x64;win-arm64;win-x64</RuntimeIdentifiers>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
|
|
||||||
<!-- TODO: Workaround for https://github.com/dotnet/runtime/issues/110000, evaluate if possible to remove later -->
|
|
||||||
<CETCompat>false</CETCompat>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(ASFVariant)' != ''">
|
<PropertyGroup Condition="'$(ASFVariant)' != ''">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<PackageVersion Include="Humanizer" Version="3.0.0-rc.30" />
|
<PackageVersion Include="Humanizer" Version="3.0.0-rc.30" />
|
||||||
<PackageVersion Include="JetBrains.Annotations.Sources" Version="2025.2.2" />
|
<PackageVersion Include="JetBrains.Annotations.Sources" Version="2025.2.2" />
|
||||||
<PackageVersion Include="Markdig.Signed" Version="0.43.0" />
|
<PackageVersion Include="Markdig.Signed" Version="0.43.0" />
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="9.0.10" />
|
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0-rc.2.25502.107" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.ResxSourceGenerator" Version="5.0.0-1.25277.114" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.ResxSourceGenerator" Version="5.0.0-1.25277.114" />
|
||||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.14.0" />
|
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.14.0" />
|
||||||
<PackageVersion Include="MSTest" Version="4.0.1" />
|
<PackageVersion Include="MSTest" Version="4.0.1" />
|
||||||
@@ -18,9 +18,8 @@
|
|||||||
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.13.0" />
|
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.13.0" />
|
||||||
<PackageVersion Include="Scalar.AspNetCore" Version="2.10.3" />
|
<PackageVersion Include="Scalar.AspNetCore" Version="2.10.3" />
|
||||||
<PackageVersion Include="SteamKit2" Version="3.3.1" />
|
<PackageVersion Include="SteamKit2" Version="3.3.1" />
|
||||||
<PackageVersion Include="System.Composition" Version="9.0.10" />
|
<PackageVersion Include="System.Composition" Version="10.0.0-rc.2.25502.107" />
|
||||||
<PackageVersion Include="System.Composition.AttributedModel" Version="9.0.10" />
|
<PackageVersion Include="System.Composition.AttributedModel" Version="10.0.0-rc.2.25502.107" />
|
||||||
<PackageVersion Include="System.Linq.Async" Version="6.0.3" />
|
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="10.0.0-rc.2.25502.107" />
|
||||||
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="9.0.10" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
15
Dockerfile
15
Dockerfile
@@ -15,7 +15,7 @@ RUN <<EOF
|
|||||||
npm run deploy --no-progress
|
npm run deploy --no-progress
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0${IMAGESUFFIX} AS build-dotnet
|
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0${IMAGESUFFIX} AS build-dotnet
|
||||||
ARG CONFIGURATION=Release
|
ARG CONFIGURATION=Release
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
@@ -76,9 +76,9 @@ RUN --mount=type=secret,id=ASF_PRIVATE_SNK --mount=type=secret,id=STEAM_TOKEN_DU
|
|||||||
done
|
done
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0${IMAGESUFFIX} AS runtime
|
FROM mcr.microsoft.com/dotnet/aspnet:10.0${IMAGESUFFIX} AS runtime
|
||||||
ENV ASF_PATH=/app
|
ENV ASF_PATH=/app
|
||||||
ENV ASF_USER=asf
|
ENV ASF_UID=1000
|
||||||
ENV ASPNETCORE_URLS=
|
ENV ASPNETCORE_URLS=
|
||||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=true
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=true
|
||||||
ENV DOTNET_NOLOGO=true
|
ENV DOTNET_NOLOGO=true
|
||||||
@@ -101,9 +101,12 @@ RUN <<EOF
|
|||||||
|
|
||||||
mkdir -p "$ASF_PATH"
|
mkdir -p "$ASF_PATH"
|
||||||
|
|
||||||
groupadd -r -g 1000 "$ASF_USER"
|
if ! id -u "$ASF_UID" >/dev/null 2>&1; then
|
||||||
useradd -r -d "$ASF_PATH" -g 1000 -u 1000 "$ASF_USER"
|
groupadd -r -g "$ASF_UID" "asf"
|
||||||
chown -hR "${ASF_USER}:${ASF_USER}" "$ASF_PATH" /asf
|
useradd -r -d "$ASF_PATH" -g "$ASF_UID" -u "$ASF_UID" "asf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
chown -hR "${ASF_UID}:${ASF_UID}" "$ASF_PATH" /asf
|
||||||
|
|
||||||
ln -s /asf/ArchiSteamFarm.sh /usr/bin/ArchiSteamFarm
|
ln -s /asf/ArchiSteamFarm.sh /usr/bin/ArchiSteamFarm
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ RUN <<EOF
|
|||||||
npm run deploy --no-progress
|
npm run deploy --no-progress
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0${IMAGESUFFIX} AS build-dotnet
|
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0${IMAGESUFFIX} AS build-dotnet
|
||||||
ARG CONFIGURATION=Release
|
ARG CONFIGURATION=Release
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
@@ -76,9 +76,9 @@ RUN --mount=type=secret,id=ASF_PRIVATE_SNK --mount=type=secret,id=STEAM_TOKEN_DU
|
|||||||
done
|
done
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/runtime-deps:9.0${IMAGESUFFIX} AS runtime
|
FROM mcr.microsoft.com/dotnet/runtime-deps:10.0${IMAGESUFFIX} AS runtime
|
||||||
ENV ASF_PATH=/app
|
ENV ASF_PATH=/app
|
||||||
ENV ASF_USER=asf
|
ENV ASF_UID=1000
|
||||||
ENV ASPNETCORE_URLS=
|
ENV ASPNETCORE_URLS=
|
||||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=true
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=true
|
||||||
ENV DOTNET_NOLOGO=true
|
ENV DOTNET_NOLOGO=true
|
||||||
@@ -101,9 +101,12 @@ RUN <<EOF
|
|||||||
|
|
||||||
mkdir -p "$ASF_PATH"
|
mkdir -p "$ASF_PATH"
|
||||||
|
|
||||||
groupadd -r -g 1000 "$ASF_USER"
|
if ! id -u "$ASF_UID" >/dev/null 2>&1; then
|
||||||
useradd -r -d "$ASF_PATH" -g 1000 -u 1000 "$ASF_USER"
|
groupadd -r -g "$ASF_UID" "asf"
|
||||||
chown -hR "${ASF_USER}:${ASF_USER}" "$ASF_PATH" /asf
|
useradd -r -d "$ASF_PATH" -g "$ASF_UID" -u "$ASF_UID" "asf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
chown -hR "${ASF_UID}:${ASF_UID}" "$ASF_PATH" /asf
|
||||||
|
|
||||||
ln -s /asf/ArchiSteamFarm-Service.sh /usr/bin/ArchiSteamFarm
|
ln -s /asf/ArchiSteamFarm-Service.sh /usr/bin/ArchiSteamFarm
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
Reference in New Issue
Block a user