mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-28 12:10:47 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1763a109c4 | ||
|
|
f57b5a2166 | ||
|
|
7210e6b86c | ||
|
|
6b241d7439 | ||
|
|
833995ca61 | ||
|
|
40531e9554 | ||
|
|
7a5a9c8a51 | ||
|
|
daae97b3d4 | ||
|
|
eeeaacb4db | ||
|
|
5324a9127d | ||
|
|
bbd267d4f0 | ||
|
|
53495e34e5 | ||
|
|
7026d8b0d5 | ||
|
|
a3b57ac50e | ||
|
|
4910692576 | ||
|
|
5147835d48 | ||
|
|
3a8d79d4da | ||
|
|
f1684c11a3 | ||
|
|
f38b6ef6dd | ||
|
|
d895f3e4bb | ||
|
|
e8b7d7d908 | ||
|
|
e7195b0e68 | ||
|
|
2983ede83d |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "ASF-WebConfigGenerator"]
|
||||
path = ASF-WebConfigGenerator
|
||||
url = https://github.com/JustArchiNET/ASF-WebConfigGenerator.git
|
||||
[submodule "ASF-ui"]
|
||||
path = ASF-ui
|
||||
url = https://github.com/JustArchiNET/ASF-ui.git
|
||||
|
||||
Submodule ASF-WebConfigGenerator deleted from 82ebd9af65
2
ASF-ui
2
ASF-ui
Submodule ASF-ui updated: 01e264f173...6e066d0edc
@@ -7,7 +7,7 @@
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="4.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace ArchiSteamFarm {
|
||||
private const string DefaultSteamTradeToken = null;
|
||||
private const ETradingPreferences DefaultTradingPreferences = ETradingPreferences.None;
|
||||
private const bool DefaultUseLoginKeys = true;
|
||||
private const byte SteamTradeTokenLength = 8;
|
||||
|
||||
private static readonly ImmutableList<EFarmingOrder> DefaultFarmingOrders = ImmutableList<EFarmingOrder>.Empty;
|
||||
private static readonly ImmutableHashSet<uint> DefaultGamesPlayedWhileIdle = ImmutableHashSet<uint>.Empty;
|
||||
@@ -288,6 +289,10 @@ namespace ArchiSteamFarm {
|
||||
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamParentalCode), SteamParentalCode));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(SteamTradeToken) && (SteamTradeToken.Length != SteamTradeTokenLength)) {
|
||||
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamTradeToken), SteamTradeToken));
|
||||
}
|
||||
|
||||
foreach ((ulong steamID, EPermission permission) in SteamUserPermissions) {
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamUserPermissions), steamID));
|
||||
|
||||
@@ -446,17 +446,62 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
|
||||
/// Accepts 2FA confirmations of given bots, requires ASF 2FA module to be active on them.
|
||||
/// </summary>
|
||||
[HttpPost("{botNames:required}/TwoFactorAuthentication/Confirmations/Accept")]
|
||||
[Obsolete]
|
||||
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GenericResponse>>), (int) HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
|
||||
public async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationConfirmationsAcceptPost(string botNames) => await TwoFactorAuthenticationConfirmationsPost(botNames, true).ConfigureAwait(false);
|
||||
public async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationConfirmationsAcceptPost(string botNames) {
|
||||
ASF.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningDeprecated, nameof(TwoFactorAuthenticationConfirmationsAcceptPost), nameof(TwoFactorAuthenticationConfirmationsPost)));
|
||||
|
||||
return await TwoFactorAuthenticationConfirmationsPost(botNames, new TwoFactorAuthenticationConfirmationsRequest(true)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Denies 2FA confirmations of given bots, requires ASF 2FA module to be active on them.
|
||||
/// </summary>
|
||||
[HttpPost("{botNames:required}/TwoFactorAuthentication/Confirmations/Cancel")]
|
||||
[Obsolete]
|
||||
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GenericResponse>>), (int) HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
|
||||
public async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationConfirmationsCancelPost(string botNames) => await TwoFactorAuthenticationConfirmationsPost(botNames, false).ConfigureAwait(false);
|
||||
public async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationConfirmationsCancelPost(string botNames) {
|
||||
ASF.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningDeprecated, nameof(TwoFactorAuthenticationConfirmationsCancelPost), nameof(TwoFactorAuthenticationConfirmationsPost)));
|
||||
|
||||
return await TwoFactorAuthenticationConfirmationsPost(botNames, new TwoFactorAuthenticationConfirmationsRequest(false)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles 2FA confirmations of given bots, requires ASF 2FA module to be active on them.
|
||||
/// </summary>
|
||||
[HttpPost("{botNames:required}/TwoFactorAuthentication/Confirmations")]
|
||||
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GenericResponse>>), (int) HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
|
||||
public async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationConfirmationsPost(string botNames, [FromBody] TwoFactorAuthenticationConfirmationsRequest request) {
|
||||
if (string.IsNullOrEmpty(botNames) || (request == null)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(botNames));
|
||||
|
||||
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, GenericResponse>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request))));
|
||||
}
|
||||
|
||||
if (request.AcceptedType.HasValue && ((request.AcceptedType.Value == MobileAuthenticator.Confirmation.EType.Unknown) || !Enum.IsDefined(typeof(MobileAuthenticator.Confirmation.EType), request.AcceptedType.Value))) {
|
||||
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, nameof(request.AcceptedType))));
|
||||
}
|
||||
|
||||
HashSet<Bot> bots = Bot.GetBots(botNames);
|
||||
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, GenericResponse>>(false, string.Format(Strings.BotNotFound, botNames)));
|
||||
}
|
||||
|
||||
IList<(bool Success, string Message)> results = await Utilities.InParallel(bots.Select(bot => bot.Actions.HandleTwoFactorAuthenticationConfirmations(request.Accept, request.AcceptedType, request.AcceptedCreatorIDs?.Count > 0 ? request.AcceptedCreatorIDs : null, request.WaitIfNeeded))).ConfigureAwait(false);
|
||||
|
||||
Dictionary<string, GenericResponse> result = new Dictionary<string, GenericResponse>(bots.Count, Bot.BotsComparer);
|
||||
|
||||
foreach (Bot bot in bots) {
|
||||
(bool success, string message) = results[result.Count];
|
||||
result[bot.BotName] = new GenericResponse(success, message);
|
||||
}
|
||||
|
||||
return Ok(new GenericResponse<IReadOnlyDictionary<string, GenericResponse>>(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches 2FA tokens of given bots, requires ASF 2FA module to be active on them.
|
||||
@@ -488,30 +533,5 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
|
||||
|
||||
return Ok(new GenericResponse<IReadOnlyDictionary<string, GenericResponse<string>>>(result));
|
||||
}
|
||||
|
||||
private async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationConfirmationsPost(string botNames, bool accept) {
|
||||
if (string.IsNullOrEmpty(botNames)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(botNames));
|
||||
|
||||
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, GenericResponse>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
|
||||
}
|
||||
|
||||
HashSet<Bot> bots = Bot.GetBots(botNames);
|
||||
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, GenericResponse>>(false, string.Format(Strings.BotNotFound, botNames)));
|
||||
}
|
||||
|
||||
IList<(bool Success, string Message)> results = await Utilities.InParallel(bots.Select(bot => bot.Actions.HandleTwoFactorAuthenticationConfirmations(accept))).ConfigureAwait(false);
|
||||
|
||||
Dictionary<string, GenericResponse> result = new Dictionary<string, GenericResponse>(bots.Count, Bot.BotsComparer);
|
||||
|
||||
foreach (Bot bot in bots) {
|
||||
(bool success, string message) = results[result.Count];
|
||||
result[bot.BotName] = new GenericResponse(success, message);
|
||||
}
|
||||
|
||||
return Ok(new GenericResponse<IReadOnlyDictionary<string, GenericResponse>>(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2020 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests {
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class TwoFactorAuthenticationConfirmationsRequest {
|
||||
/// <summary>
|
||||
/// Specifies the target action, whether we should accept the confirmations (true), or decline them (false).
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
public readonly bool Accept;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the type of confirmations to handle. If not provided, all confirmation types are considered for an action.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public readonly MobileAuthenticator.Confirmation.EType? AcceptedType;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies whether we should wait for the confirmations to arrive, in case they're not available immediately. This option makes sense only if <see cref="AcceptedCreatorIDs" /> is specified as well, and in this case ASF will add a few more tries if needed to ensure that all specified IDs are handled. Useful if confirmations are generated with a delay on Steam network side, which happens fairly often.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public readonly bool WaitIfNeeded;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies IDs of the confirmations that we're supposed to handle. CreatorID of the confirmation is equal to ID of the object that triggered it - e.g. ID of the trade offer, or ID of the market listing. If not provided, or empty array, all confirmation IDs are considered for an action.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ImmutableHashSet<ulong> AcceptedCreatorIDs { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A helper property which works the same as <see cref="AcceptedCreatorIDs" /> but with values written as strings - for javascript compatibility purposes. Use either this one, or <see cref="AcceptedCreatorIDs" />, not both.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(AcceptedCreatorIDs), Required = Required.DisallowNull)]
|
||||
public ImmutableHashSet<string> SAcceptedCreatorIDs {
|
||||
set {
|
||||
if (value == null) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(value));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<ulong> acceptedCreatorIDs = new HashSet<ulong>(value.Count);
|
||||
|
||||
foreach (string creatorIDText in value) {
|
||||
if (!ulong.TryParse(creatorIDText, out ulong creatorID) || (creatorID == 0)) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(SAcceptedCreatorIDs)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
acceptedCreatorIDs.Add(creatorID);
|
||||
}
|
||||
|
||||
AcceptedCreatorIDs = acceptedCreatorIDs.ToImmutableHashSet();
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
internal TwoFactorAuthenticationConfirmationsRequest(bool accept) => Accept = accept;
|
||||
|
||||
[JsonConstructor]
|
||||
private TwoFactorAuthenticationConfirmationsRequest() { }
|
||||
}
|
||||
}
|
||||
@@ -170,6 +170,7 @@ namespace ArchiSteamFarm.IPC {
|
||||
}
|
||||
);
|
||||
|
||||
options.CustomSchemaIds(type => type.GetUnifiedName());
|
||||
options.EnableAnnotations(true);
|
||||
options.SchemaFilter<EnumSchemaFilter>();
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
// Bot must have at least one accepted matchable type set
|
||||
if ((Bot.BotConfig.MatchableTypes.Count == 0) || Bot.BotConfig.MatchableTypes.All(type => !AcceptedMatchableTypes.Contains(type))) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.WarningFailedWithError, nameof(Bot.BotConfig.MatchableTypes) + ": " + Bot.BotConfig.MatchableTypes));
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.WarningFailedWithError, nameof(Bot.BotConfig.MatchableTypes) + ": " + string.Join(", ", Bot.BotConfig.MatchableTypes)));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -412,10 +412,26 @@ namespace ArchiSteamFarm {
|
||||
|
||||
Bot.ArchiLogger.LogGenericTrace(listedUser.SteamID + "...");
|
||||
|
||||
byte? holdDuration = await Bot.ArchiWebHandler.GetTradeHoldDurationForUser(listedUser.SteamID, listedUser.TradeToken).ConfigureAwait(false);
|
||||
|
||||
if (!holdDuration.HasValue) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(holdDuration)));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (holdDuration.Value > 0) {
|
||||
if (holdDuration.Value > ASF.GlobalConfig.MaxTradeHoldDuration) {
|
||||
Bot.ArchiLogger.LogGenericTrace(holdDuration.Value + " > " + ASF.GlobalConfig.MaxTradeHoldDuration);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<Steam.Asset> theirInventory;
|
||||
|
||||
try {
|
||||
theirInventory = await Bot.ArchiWebHandler.GetInventoryAsync(listedUser.SteamID).Where(item => (!listedUser.MatchEverything || item.Tradable) && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity))).ToHashSetAsync().ConfigureAwait(false);
|
||||
theirInventory = await Bot.ArchiWebHandler.GetInventoryAsync(listedUser.SteamID).Where(item => (!listedUser.MatchEverything || item.Tradable) && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity)) && ((holdDuration.Value == 0) || !(((item.Type == Steam.Asset.EType.FoilTradingCard) || (item.Type == Steam.Asset.EType.TradingCard)) && CardsFarmer.SalesBlacklist.Contains(item.RealAppID)))).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException) {
|
||||
continue;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>4.2.3.7</Version>
|
||||
<Version>4.2.3.8</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
$archiCrowdinPath = 'tools\ArchiCrowdin'
|
||||
$archiCrowdinScriptPath = "$archiCrowdinPath\archi.ps1"
|
||||
|
||||
$crowdinConfigFileName = 'crowdin.yml'
|
||||
$crowdinIdentityFileName = 'crowdin_identity.yml'
|
||||
$crowdinIdentityPath = "$archiCrowdinPath\$crowdinIdentityFileName"
|
||||
|
||||
$archiTargets = @('ASF-ui', 'ASF-WebConfigGenerator')
|
||||
|
||||
Push-Location "$PSScriptRoot"
|
||||
|
||||
try {
|
||||
for ($i = 0; ($i -lt 3) -and (!(Test-Path "$crowdinConfigFileName" -PathType Leaf)); $i++) {
|
||||
Set-Location ..
|
||||
}
|
||||
|
||||
if (!(Test-Path "$crowdinConfigFileName" -PathType Leaf)) {
|
||||
throw "$crowdinConfigFileName could not be found, aborting."
|
||||
}
|
||||
|
||||
if (!(Test-Path "$archiCrowdinScriptPath" -PathType Leaf)) {
|
||||
throw "$archiCrowdinScriptPath could not be found, aborting."
|
||||
}
|
||||
|
||||
if (!(Test-Path "$crowdinIdentityPath" -PathType Leaf)) {
|
||||
throw "$crowdinIdentityPath could not be found, aborting."
|
||||
}
|
||||
|
||||
& "$archiCrowdinScriptPath" -t:$archiTargets -d -c -p # Download and commit all independent submodules that are part of ASF project
|
||||
& "$archiCrowdinScriptPath" -t:wiki -c -p # Wiki submodule depends on us, we do this one more time before in order to ensure that tree is up-to-date (e.g. branch is master before we start modifying files in the next step)
|
||||
& "$archiCrowdinScriptPath" -d -p -rs:no # Download translations for the main project, which also includes wiki submodule as of now
|
||||
& "$archiCrowdinScriptPath" -t:wiki -c -p # Commit the wiki submodule that we updated in the previous step
|
||||
& "$archiCrowdinScriptPath" -c # Commit the main project and references of all submodules
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
pause
|
||||
2
wiki
2
wiki
Submodule wiki updated: 6a123c4dda...424e0133fd
Reference in New Issue
Block a user