Compare commits

..

82 Commits

Author SHA1 Message Date
Renovate Bot
a4374389b8 Update dependency ConfigureAwaitChecker.Analyzer to v5.0.0.1 2022-05-26 03:12:12 +00:00
ArchiBot
082cab42df Automatic translations update 2022-05-26 02:38:09 +00:00
Renovate Bot
3ff80b37f3 Update ASF-ui digest to 1bf5b24 2022-05-25 20:21:25 +00:00
JustArchi
07c354f9e7 Commit the most misc optimization in history
I found it accidentally, lol
2022-05-25 20:04:54 +02:00
Sebastian Göls
b83f8fc669 Update Program.cs (#2589) 2022-05-25 17:18:06 +02:00
Renovate Bot
d6a2f53ab0 Update wiki digest to f26dbc5 2022-05-25 11:51:00 +00:00
JustArchi
0261623ea9 Expose FinalUri in BasicResponse for plugins usage 2022-05-24 12:25:43 +02:00
JustArchi
b5ca484c2b Add ReturnRedirections for plugins usage
This will allow caller to handle redirections manually
2022-05-24 12:13:54 +02:00
Renovate Bot
a7c30e4878 Update ASF-ui digest to a790c6c 2022-05-22 03:51:41 +00:00
Renovate Bot
f26a4ae864 Update ASF-ui digest to 24ff55f 2022-05-21 05:09:18 +00:00
Renovate Bot
c2018b53a5 Update actions/upload-artifact action to v3.1.0 2022-05-20 20:28:10 +00:00
JustArchi
55421bb29f Throw on lack of previousMethodName
I don't believe we should support those calls for anything that doesn't supply it. Actually add another layer of safeguards.
2022-05-20 21:36:22 +02:00
Renovate Bot
52eabe4daf Update ASF-ui digest to 46fe13d 2022-05-20 05:16:48 +00:00
ArchiBot
86fc8a765c Automatic translations update 2022-05-20 02:34:05 +00:00
JustArchi
9162752b99 Misc 2022-05-19 21:38:40 +02:00
JustArchi
4436e8dc43 Add STD command trigger for STD plugin 2022-05-19 21:34:57 +02:00
JustArchi
1f0b996cf5 Improve login procedure
- Allow user to recover from SteamGuard/2FA failures when inputting manually
- Unify login failures in a single mechanism
- Add fallback for Steam informing us about lack of 2FA code when actually having mobile authenticator and supplying it (ultra rare screwup)
2022-05-19 15:33:53 +02:00
ArchiBot
4dc7acb914 Automatic translations update 2022-05-19 02:39:10 +00:00
Renovate Bot
d570a17532 Update wiki digest to 6958aab 2022-05-18 14:59:10 +00:00
Renovate Bot
e5184adede Update ASF-ui digest to 790ff09 2022-05-18 14:58:40 +00:00
JustArchi
13a5fa7c02 Misc 2022-05-18 11:45:31 +02:00
JustArchi
c698fe7b07 Bump 2022-05-18 11:31:49 +02:00
JustArchi
a08c85e40b Increase interactive console responsiveness, misc
Previously we were sleeping always, also after execution of the command and after wrong keys being pressed, which resulted in excessive delay if user mashed his keyboard like a madman before hitting c to enter the console, entirely unnecessarily.
2022-05-18 11:30:46 +02:00
JustArchi
055af32219 Address missed NLog breaking change 2022-05-18 11:20:35 +02:00
ArchiBot
080b500ebf Automatic translations update 2022-05-18 02:33:30 +00:00
JustArchi
4a329b0b15 Bump 2022-05-17 23:03:42 +02:00
JustArchi
e2494960ae Bump 2022-05-17 23:02:14 +02:00
JustArchi
2e987ccee6 Address NLog changes 2022-05-17 20:12:57 +02:00
renovate[bot]
99284e22c9 Update dependency NLog.Web.AspNetCore to v5 (#2579)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-05-17 20:09:34 +02:00
renovate[bot]
37eac5844e Update ASF-ui digest to 664643e (#2578)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-05-17 11:41:52 +02:00
Renovate Bot
35f295a860 Update ASF-ui digest to 8d0abfb 2022-05-16 19:07:27 +00:00
Renovate Bot
29d047271e Update actions/setup-node action to v3.2.0 2022-05-16 14:03:52 +00:00
Renovate Bot
948a86bfc9 Update ASF-ui digest to 2fe4a70 2022-05-16 04:50:08 +00:00
ArchiBot
f853c61821 Automatic translations update 2022-05-16 02:25:24 +00:00
JustArchi
5b1cb16c98 Stop wasting CPU cycles! 2022-05-13 19:33:08 +02:00
JustArchi
bdac1b2782 Bump 2022-05-13 18:22:24 +02:00
JustArchi
7532b89fd0 Closes #2572
At least the code is now shorter, lol
2022-05-13 18:15:15 +02:00
JustArchi
7cd351d1cd Misc
This applies only to Debug builds, as Release ones don't use checked arithmetic anyway
2022-05-13 18:12:31 +02:00
Renovate Bot
9c8d63318e Update ASF-ui digest to bb59242 2022-05-13 05:08:45 +00:00
ArchiBot
f0c0e07489 Automatic translations update 2022-05-13 02:42:57 +00:00
ArchiBot
d2e79ff3a4 Automatic translations update 2022-05-12 02:33:43 +00:00
Renovate Bot
ab7b998e3b Update dependency Microsoft.NET.Test.Sdk to v17.2.0 2022-05-11 21:19:10 +00:00
Łukasz Domeradzki
9c88d14c8e Resolve NU1507 (#2575)
* Attempt to resolve NU1507

* Let's try this then

* Revert "Let's try this then"

This reverts commit 86ef6f9abf.

* How about this

* And this?

* So why not this?

* And this?

* Revert "And this?"

This reverts commit e43fc83dcc.

* Revert "So why not this?"

This reverts commit e630dd8365.
2022-05-11 20:11:58 +02:00
ArchiBot
9a3c3bdbaf Automatic translations update 2022-05-11 02:35:21 +00:00
Renovate Bot
7b3598af20 Update dotnet monorepo to v3.1.25 2022-05-10 19:23:40 +00:00
Renovate Bot
35d2156855 Update ASF-ui digest to b22bef8 2022-05-10 16:40:51 +00:00
JustArchi
d589da7a39 Bump 2022-05-10 11:14:11 +02:00
JustArchi
c10de94bd0 Closes #2571 2022-05-10 11:11:45 +02:00
Renovate Bot
d164296d7e Update actions/setup-dotnet action to v2.1.0 2022-05-09 10:21:58 +00:00
Renovate Bot
b378a76072 Update ASF-ui digest to 0ed48ea 2022-05-08 22:02:09 +00:00
Archi
263a2db476 CI: Remove excessive continue on errors 2022-05-08 23:01:45 +02:00
Renovate Bot
61549fc983 Update ASF-ui digest to 1f02912 2022-05-07 03:46:37 +00:00
ArchiBot
19aad04143 Automatic translations update 2022-05-07 02:24:04 +00:00
Renovate Bot
5a5f3c6786 Update ASF-ui digest to a9ddf4a 2022-05-06 22:30:53 +00:00
Renovate Bot
bd68df2fd6 Update crowdin/github-action action to v1.4.9 2022-05-06 16:18:34 +00:00
renovate[bot]
2a97644468 Update docker/build-push-action action to v3 (#2565)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-05-06 10:20:55 +02:00
renovate[bot]
5304ca3e07 Update docker/login-action action to v2 (#2566)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-05-06 10:20:50 +02:00
renovate[bot]
f0471ac0eb Update docker/setup-buildx-action action to v2 (#2567)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-05-06 10:20:42 +02:00
ArchiBot
b0e7f1963c Automatic translations update 2022-05-06 02:27:24 +00:00
Renovate Bot
78990e8aff Update wiki digest to b43bf17 2022-05-05 13:03:59 +00:00
Renovate Bot
b871970d85 Update ASF-ui digest to 722f6b2 2022-05-05 00:18:06 +00:00
ArchiBot
d563a20288 Automatic translations update 2022-05-04 02:36:40 +00:00
Renovate Bot
b2fefa4476 Update wiki digest to 37d8dcc 2022-05-03 11:51:02 +00:00
ArchiBot
840cf25ea4 Automatic translations update 2022-04-30 02:36:10 +00:00
Renovate Bot
79587f68d7 Update ASF-ui digest to a351077 2022-04-30 00:09:30 +00:00
Archi
45adf9c1a1 Bump 2022-04-29 20:25:59 +02:00
Archi
1dcf98c849 Fix SteamPassword input
Asking for password with encryption enabled always resulted in an error, as the password wasn't properly set to the plaintext and we were back to square one.

The previous logic was overly complex, I don't know why, this should achieve the same and be much easier to understand while at it.
2022-04-29 17:55:33 +02:00
ArchiBot
a826b7f9b7 Automatic translations update 2022-04-29 02:37:09 +00:00
Renovate Bot
85c8397cf7 Update docker/setup-buildx-action action to v1.7.0 2022-04-28 11:01:51 +00:00
ArchiBot
dbf1c1ba51 Automatic translations update 2022-04-28 02:50:54 +00:00
Renovate Bot
359439e306 Update ASF-ui digest to 892742c 2022-04-27 13:48:33 +00:00
ArchiBot
763766e092 Automatic translations update 2022-04-27 02:42:35 +00:00
Renovate Bot
a4a347e957 Update mstest monorepo to v2.2.10 2022-04-26 22:17:23 +00:00
Renovate Bot
844ca93647 Update wiki digest to 0c633a3 2022-04-26 18:49:18 +00:00
Renovate Bot
16fe445ea9 Update ASF-ui digest to 83c8a83 2022-04-26 18:48:48 +00:00
Renovate Bot
34bf8fb84f Update crazy-max/ghaction-import-gpg action to v4.4.0 2022-04-25 14:36:52 +00:00
Renovate Bot
4873cd337a Update ASF-ui digest to 5554b10 2022-04-25 03:07:32 +00:00
ArchiBot
8c0249a62d Automatic translations update 2022-04-25 02:33:43 +00:00
ArchiBot
220ecf0c38 Automatic translations update 2022-04-24 02:24:03 +00:00
Renovate Bot
ebd79425f4 Update wiki digest to 370d1b3 2022-04-23 18:48:11 +00:00
Renovate Bot
2eaf934dde Update dependency Markdig.Signed to v0.30.2 2022-04-23 14:22:52 +00:00
Archi
599cd9bff8 Bump 2022-04-23 15:02:37 +02:00
32 changed files with 685 additions and 341 deletions

View File

@@ -24,7 +24,7 @@ jobs:
submodules: recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v2.0.0
uses: actions/setup-dotnet@v2.1.0
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
@@ -39,7 +39,7 @@ jobs:
- name: Upload latest strings for translation on Crowdin
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && matrix.configuration == 'Release' && startsWith(matrix.os, 'ubuntu-') }}
uses: crowdin/github-action@1.4.8
uses: crowdin/github-action@1.4.9
with:
crowdin_branch_name: main
config: '.github/crowdin.yml'

View File

@@ -22,10 +22,10 @@ jobs:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1.6.0
uses: docker/setup-buildx-action@v2.0.0
- name: Build ${{ matrix.configuration }} Docker image from ${{ matrix.file }}
uses: docker/build-push-action@v2.10.0
uses: docker/build-push-action@v3.0.0
with:
context: .
file: ${{ matrix.file }}

View File

@@ -20,17 +20,17 @@ jobs:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1.6.0
uses: docker/setup-buildx-action@v2.0.0
- name: Login to ghcr.io
uses: docker/login-action@v1.14.1
uses: docker/login-action@v2.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@v1.14.1
uses: docker/login-action@v2.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -55,7 +55,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile.Service
uses: docker/build-push-action@v2.10.0
uses: docker/build-push-action@v3.0.0
with:
context: .
file: Dockerfile.Service

View File

@@ -21,17 +21,17 @@ jobs:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1.6.0
uses: docker/setup-buildx-action@v2.0.0
- name: Login to ghcr.io
uses: docker/login-action@v1.14.1
uses: docker/login-action@v2.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@v1.14.1
uses: docker/login-action@v2.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -55,7 +55,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile
uses: docker/build-push-action@v2.10.0
uses: docker/build-push-action@v3.0.0
with:
context: .
platforms: ${{ env.PLATFORMS }}
@@ -70,7 +70,6 @@ jobs:
push: true
- name: Update DockerHub repository description
continue-on-error: true
uses: peter-evans/dockerhub-description@v3.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}

View File

@@ -21,17 +21,17 @@ jobs:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1.6.0
uses: docker/setup-buildx-action@v2.0.0
- name: Login to ghcr.io
uses: docker/login-action@v1.14.1
uses: docker/login-action@v2.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@v1.14.1
uses: docker/login-action@v2.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -56,7 +56,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile
uses: docker/build-push-action@v2.10.0
uses: docker/build-push-action@v3.0.0
with:
context: .
platforms: ${{ env.PLATFORMS }}

View File

@@ -30,7 +30,7 @@ jobs:
submodules: recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v2.0.0
uses: actions/setup-dotnet@v2.1.0
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
@@ -38,7 +38,7 @@ jobs:
run: dotnet --info
- name: Setup Node.js with npm
uses: actions/setup-node@v3.1.1
uses: actions/setup-node@v3.2.0
with:
check-latest: true
node-version: ${{ env.NODE_JS_VERSION }}
@@ -339,58 +339,50 @@ jobs:
Get-Job | Receive-Job -Wait
- name: Upload ASF-generic
continue-on-error: true
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.os }}_ASF-generic
path: out/ASF-generic.zip
- name: Upload ASF-generic-netf
continue-on-error: true
if: startsWith(matrix.os, 'windows-')
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.os }}_ASF-generic-netf
path: out/ASF-generic-netf.zip
- name: Upload ASF-linux-arm
continue-on-error: true
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.os }}_ASF-linux-arm
path: out/ASF-linux-arm.zip
- name: Upload ASF-linux-arm64
continue-on-error: true
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.os }}_ASF-linux-arm64
path: out/ASF-linux-arm64.zip
- name: Upload ASF-linux-x64
continue-on-error: true
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.os }}_ASF-linux-x64
path: out/ASF-linux-x64.zip
- name: Upload ASF-osx-arm64
continue-on-error: true
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.os }}_ASF-osx-arm64
path: out/ASF-osx-arm64.zip
- name: Upload ASF-osx-x64
continue-on-error: true
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.os }}_ASF-osx-x64
path: out/ASF-osx-x64.zip
- name: Upload ASF-win-x64
continue-on-error: true
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.os }}_ASF-win-x64
path: out/ASF-win-x64.zip
@@ -456,7 +448,7 @@ jobs:
path: out
- name: Import GPG key for signing
uses: crazy-max/ghaction-import-gpg@v4.3.0
uses: crazy-max/ghaction-import-gpg@v4.4.0
with:
gpg_private_key: ${{ secrets.ARCHIBOT_GPG_PRIVATE_KEY }}
@@ -473,15 +465,13 @@ jobs:
)
- name: Upload SHA512SUMS
continue-on-error: true
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: SHA512SUMS
path: out/SHA512SUMS
- name: Upload SHA512SUMS.sign
continue-on-error: true
uses: actions/upload-artifact@v3.0.0
uses: actions/upload-artifact@v3.1.0
with:
name: SHA512SUMS.sign
path: out/SHA512SUMS.sign

View File

@@ -26,7 +26,7 @@ jobs:
git reset --hard origin/master
- name: Download latest translations from Crowdin
uses: crowdin/github-action@1.4.8
uses: crowdin/github-action@1.4.9
with:
upload_sources: false
download_translations: true
@@ -38,7 +38,7 @@ jobs:
token: ${{ secrets.ASF_CROWDIN_API_TOKEN }}
- name: Import GPG key for signing
uses: crazy-max/ghaction-import-gpg@v4.3.0
uses: crazy-max/ghaction-import-gpg@v4.4.0
with:
gpg_private_key: ${{ secrets.ARCHIBOT_GPG_PRIVATE_KEY }}
git_config_global: true

2
ASF-ui

Submodule ASF-ui updated: 5a6f341119...1bf5b24f3a

View File

@@ -62,34 +62,119 @@
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="PluginDisabledMissingBuildToken" xml:space="preserve">
<value>{0} on poistettu käytöstä puuttuvan koontitunnuksen vuoksi</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginDisabledInConfig" xml:space="preserve">
<value>{0} on tällä hetkellä poistettu käytöstä asetuksistasi. Jos haluat auttaa SteamDB:tä tietojen lähettämisessä, ole hyvä ja tutustu wikimme.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} on alustettu onnistuneesti, kiitos etukäteen avustasi. Ensimmäinen lähetys tapahtuu noin {1} jälkeen.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} ei voitu ladata. Uusi instanssi alustetaan...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>
</data>
<data name="BotNoAppsToRefresh" xml:space="preserve">
<value>Ei ole sovelluksia, jotka vaatisivat päivitystä tässä botin instanssissa.</value>
</data>
<data name="BotRetrievingTotalAppAccessTokens" xml:space="preserve">
<value>Haetaan yhteensä {0} sovelluksen käyttötunnisteita...</value>
<comment>{0} will be replaced by the number (total count) of app access tokens being retrieved</comment>
</data>
<data name="BotRetrievingAppAccessTokens" xml:space="preserve">
<value>Haetaan {0} sovelluksen käyttötunnisteita...</value>
<comment>{0} will be replaced by the number (count this batch) of app access tokens being retrieved</comment>
</data>
<data name="BotFinishedRetrievingAppAccessTokens" xml:space="preserve">
<value>Saatiin haettua {0} sovelluksen käyttötunnisteet.</value>
<comment>{0} will be replaced by the number (count this batch) of app access tokens retrieved</comment>
</data>
<data name="BotFinishedRetrievingTotalAppAccessTokens" xml:space="preserve">
<value>Saatiin haettua yhteensä {0} sovelluksen käyttötunnisteet.</value>
<comment>{0} will be replaced by the number (total count) of app access tokens retrieved</comment>
</data>
<data name="BotRetrievingTotalDepots" xml:space="preserve">
<value>Haetaan kaikkia depotteja yhteensä {0} sovellukselle...</value>
<comment>{0} will be replaced by the number (total count) of apps being retrieved</comment>
</data>
<data name="BotRetrievingAppInfos" xml:space="preserve">
<value>Haetaan {0} sovelluksen tietoja...</value>
<comment>{0} will be replaced by the number (count this batch) of app infos being retrieved</comment>
</data>
<data name="BotFinishedRetrievingAppInfos" xml:space="preserve">
<value>Saatiin haettua {0} sovelluksen tiedot.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotRetrievingDepotKeys" xml:space="preserve">
<value>Haetaan {0} depot-avainta...</value>
<comment>{0} will be replaced by the number (count this batch) of depot keys being retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>Saatiin haettua {0} depot-avainta.</value>
<comment>{0} will be replaced by the number (count this batch) of depot keys retrieved</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>Saatiin haettua kaikki depot-avaimet yhteensä {0} sovellukselle.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>
</data>
<data name="SubmissionNoNewData" xml:space="preserve">
<value>Uutta dataa ei ole lähetettäväksi, kaikki on ajan tasalla.</value>
</data>
<data name="SubmissionNoContributorSet" xml:space="preserve">
<value>Tietoja ei voitu lähettää, koska ei ole voimassa olevaa SteamID-ryhmää, jonka voisimme luokitella osallistujaksi. Harkitse ominaisuuden {0} asettamista.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SteamOwnerID") that the user is expected to set</comment>
</data>
<data name="SubmissionInProgress" xml:space="preserve">
<value>Lähetetään yhteensä {0}/{1}/{2} rekisteröityjä sovelluksia/paketteja/varikoita...</value>
<comment>{0} will be replaced by the number of app access tokens being submitted, {1} will be replaced by the number of package access tokens being submitted, {2} will be replaced by the number of depot keys being submitted</comment>
</data>
<data name="SubmissionFailedTooManyRequests" xml:space="preserve">
<value>Lähetys epäonnistui liian monen pyynnön vuoksi, yritämme uudelleen noin {0} kuluttua.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="SubmissionSuccessful" xml:space="preserve">
<value>Tiedot on lähetetty onnistuneesti. Palvelin on rekisteröinyt yhteensä uusia sovelluksia/paketteja/depoteja: {0} ({1} vahvistettu)/{2} ({3} vahvistettu)/{4} ({5} vahvistettu).</value>
<comment>{0} will be replaced by the number of new app access tokens that the server has registered, {1} will be replaced by the number of verified app access tokens that the server has registered, {2} will be replaced by the number of new package access tokens that the server has registered, {3} will be replaced by the number of verified package access tokens that the server has registered, {4} will be replaced by the number of new depot keys that the server has registered, {5} will be replaced by the number of verified depot keys that the server has registered</comment>
</data>
<data name="SubmissionSuccessfulNewApps" xml:space="preserve">
<value>Uudet sovellukset: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedApps" xml:space="preserve">
<value>Vahvistetut sovellukset: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewPackages" xml:space="preserve">
<value>Uudet paketit: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedPackages" xml:space="preserve">
<value>Vahvistetut paketit: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewDepots" xml:space="preserve">
<value>Uudet depotit: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedDepots" xml:space="preserve">
<value>Vahvistetut depotit: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="PluginSecretListInitialized" xml:space="preserve">
<value>{0} alustettu, laajennus ei käsittele yhtään näistä: {1}.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SecretPackageIDs"), {1} will be replaced by list of the objects (IDs, numbers), separated by a comma</comment>
</data>
<data name="LoadingGlobalCache" xml:space="preserve">
<value>Ladataan STD:n globaalia välimuistia...</value>
</data>
<data name="ValidatingGlobalCacheIntegrity" xml:space="preserve">
<value>Tarkistetaan STD-välimuistin eheys...</value>
</data>
<data name="GlobalCacheIntegrityValidationFailed" xml:space="preserve">
<value>STD:n globaalin välimuistin eheyden varmistaminen epäonnistui. Tämä viittaa mahdolliseen tiedoston/muistin korruptioon, uusi instanssi käynnistetään sen sijaan.</value>
</data>
</root>

View File

@@ -24,10 +24,11 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper;
internal static class SharedInfo {
internal const byte ApiVersion = 2;
internal const byte AppInfosPerSingleRequest = byte.MaxValue;
internal const byte HoursBetweenUploads = 24;
internal const byte MaximumHoursBetweenRefresh = 8; // Per single bot account, makes sense to be 2 or 3 times less than MinimumHoursBetweenUploads
internal const byte MaximumMinutesBeforeFirstUpload = 60; // Must be greater or equal to MinimumMinutesBeforeFirstUpload
internal const byte MinimumHoursBetweenUploads = 24;
internal const byte MinimumMinutesBeforeFirstUpload = 10; // Must be less or equal to MaximumMinutesBeforeFirstUpload
internal const byte MinimumMinutesBetweenUploads = 5; // Rate limiting for the server
internal const string ServerURL = "https://asf-token-dumper.xpaw.me";
internal const string Token = "STEAM_TOKEN_DUMPER_TOKEN"; // This is filled automatically during our CI build with API key provided by xPaw for ASF project

View File

@@ -23,6 +23,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Composition;
using System.Globalization;
using System.Linq;
@@ -43,7 +44,7 @@ using SteamKit2;
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper;
[Export(typeof(IPlugin))]
internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotSteamClient, ISteamPICSChanges {
internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotCommand2, IBotSteamClient, ISteamPICSChanges {
[JsonProperty]
internal static SteamTokenDumperConfig? Config { get; private set; }
@@ -53,6 +54,7 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotS
private static readonly Timer SubmissionTimer = new(SubmitData);
private static GlobalCache? GlobalCache;
private static DateTimeOffset LastUploadAt = DateTimeOffset.MinValue;
[JsonProperty]
public override string Name => nameof(SteamTokenDumperPlugin);
@@ -138,12 +140,44 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotS
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (SubmissionSemaphore) {
SubmissionTimer.Change(startIn, TimeSpan.FromHours(SharedInfo.MinimumHoursBetweenUploads));
SubmissionTimer.Change(startIn, TimeSpan.FromHours(SharedInfo.HoursBetweenUploads));
}
ASF.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.PluginInitializedAndEnabled, nameof(SteamTokenDumperPlugin), startIn.ToHumanReadable()));
}
public Task<string?> OnBotCommand(Bot bot, EAccess access, string message, string[] args, ulong steamID = 0) {
ArgumentNullException.ThrowIfNull(bot);
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
if ((args == null) || (args.Length == 0)) {
throw new ArgumentNullException(nameof(args));
}
switch (args[0].ToUpperInvariant()) {
case "STD" when access >= EAccess.Owner:
TimeSpan minimumTimeBetweenUpload = TimeSpan.FromMinutes(SharedInfo.MinimumMinutesBetweenUploads);
if (LastUploadAt + minimumTimeBetweenUpload > DateTimeOffset.UtcNow) {
return Task.FromResult((string?) string.Format(CultureInfo.CurrentCulture, Strings.SubmissionFailedTooManyRequests, minimumTimeBetweenUpload.ToHumanReadable()));
}
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (SubmissionSemaphore) {
SubmissionTimer.Change(TimeSpan.Zero, TimeSpan.FromHours(SharedInfo.HoursBetweenUploads));
}
return Task.FromResult((string?) ArchiSteamFarm.Localization.Strings.Done);
case "STD" when access > EAccess.None:
return Task.FromResult((string?) ArchiSteamFarm.Localization.Strings.ErrorAccessDenied);
default:
return Task.FromResult((string?) null);
}
}
public async Task OnBotDestroy(Bot bot) {
ArgumentNullException.ThrowIfNull(bot);
@@ -460,6 +494,10 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotS
throw new InvalidOperationException(nameof(ASF.WebBrowser));
}
if (LastUploadAt + TimeSpan.FromMinutes(SharedInfo.MinimumMinutesBetweenUploads) > DateTimeOffset.UtcNow) {
return;
}
if (!await SubmissionSemaphore.WaitAsync(0).ConfigureAwait(false)) {
return;
}
@@ -496,6 +534,9 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotS
return;
}
// We've communicated with the server and didn't timeout, regardless of the success, this was the last upload attempt
LastUploadAt = DateTimeOffset.UtcNow;
if (response.StatusCode.IsClientErrorCode()) {
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, response.StatusCode));
@@ -510,7 +551,7 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotS
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (SubmissionSemaphore) {
SubmissionTimer.Change(startIn, TimeSpan.FromHours(SharedInfo.MinimumHoursBetweenUploads));
SubmissionTimer.Change(startIn, TimeSpan.FromHours(SharedInfo.HoursBetweenUploads));
}
ASF.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.SubmissionFailedTooManyRequests, startIn.ToHumanReadable()));

View File

@@ -164,6 +164,9 @@ public static class Utilities {
[PublicAPI]
public static bool IsClientErrorCode(this HttpStatusCode statusCode) => statusCode is >= HttpStatusCode.BadRequest and < HttpStatusCode.InternalServerError;
[PublicAPI]
public static bool IsRedirectionCode(this HttpStatusCode statusCode) => statusCode is >= HttpStatusCode.Ambiguous and < HttpStatusCode.BadRequest;
[PublicAPI]
public static bool IsServerErrorCode(this HttpStatusCode statusCode) => statusCode is >= HttpStatusCode.InternalServerError and < (HttpStatusCode) 600;

View File

@@ -34,7 +34,6 @@ using ArchiSteamFarm.NLog.Targets;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog.Web;
@@ -76,37 +75,24 @@ internal static class ArchiKestrel {
// Set default content root
builder.UseContentRoot(SharedInfo.HomeDirectory);
// Firstly initialize settings that user is free to override
builder.ConfigureLogging(
static logging => {
logging.ClearProviders();
logging.SetMinimumLevel(Debugging.IsUserDebugging ? LogLevel.Trace : LogLevel.Warning);
}
);
// Check if custom config is available
string absoluteConfigDirectory = Path.Combine(Directory.GetCurrentDirectory(), SharedInfo.ConfigDirectory);
string customConfigPath = Path.Combine(absoluteConfigDirectory, SharedInfo.IPCConfigFile);
bool customConfigExists = File.Exists(customConfigPath);
if (customConfigExists) {
if (Debugging.IsDebugConfigured) {
try {
string json = await File.ReadAllTextAsync(customConfigPath).ConfigureAwait(false);
if (customConfigExists && Debugging.IsDebugConfigured) {
try {
string json = await File.ReadAllTextAsync(customConfigPath).ConfigureAwait(false);
if (!string.IsNullOrEmpty(json)) {
JObject jObject = JObject.Parse(json);
if (!string.IsNullOrEmpty(json)) {
JObject jObject = JObject.Parse(json);
ASF.ArchiLogger.LogGenericDebug($"{SharedInfo.IPCConfigFile}: {jObject.ToString(Formatting.Indented)}");
}
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
ASF.ArchiLogger.LogGenericDebug($"{SharedInfo.IPCConfigFile}: {jObject.ToString(Formatting.Indented)}");
}
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
}
// Use custom config for logging configuration
builder.ConfigureLogging(static (hostingContext, logging) => logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")));
}
// Enable NLog integration for logging

View File

@@ -123,7 +123,10 @@ public sealed class BotController : ArchiController {
}
if (!request.BotConfig.IsSteamPasswordSet && bot.BotConfig.IsSteamPasswordSet) {
request.BotConfig.SetDecryptedSteamPassword(await bot.BotConfig.GetDecryptedSteamPassword().ConfigureAwait(false));
request.BotConfig.SteamPassword = bot.BotConfig.SteamPassword;
// Since we're inheriting the password, we should also inherit the format, whatever that might be
request.BotConfig.PasswordFormat = bot.BotConfig.PasswordFormat;
}
if (!request.BotConfig.IsSteamParentalCodeSet && bot.BotConfig.IsSteamParentalCodeSet) {

View File

@@ -658,7 +658,10 @@
<data name="IPCConfigChanged" xml:space="preserve">
<value>IPC настройките са били променени!</value>
</data>
<data name="BotTradeOfferResult" xml:space="preserve">
<value>Предложението за размяна {0} е определено като {1} поради {2}.</value>
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
</data>
<data name="Result" xml:space="preserve">
<value>Резултат: {0}</value>
@@ -672,6 +675,10 @@
<data name="ErrorConfigDirectoryNotFound" xml:space="preserve">
<value>Папката с настройките не може да бъде открита, прекратяване!</value>
</data>
<data name="BotIdlingSelectedGames" xml:space="preserve">
<value>Играят се избраните {0}: {1}</value>
<comment>{0} will be replaced by internal name of the config property (e.g. "GamesPlayedWhileIdle"), {1} will be replaced by comma-separated list of appIDs that user has chosen</comment>
</data>
@@ -685,6 +692,7 @@
<data name="PatchingFiles" xml:space="preserve">
<value>Пачват се ASF файлове...</value>
</data>
</root>

View File

@@ -63,7 +63,7 @@
</value>
</resheader>
<data name="AcceptingTrade" xml:space="preserve">
<value>Hyväksytään vaihtoa: {0}</value>
<value>Hyväksytään vaihtokauppaa: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="AutoUpdateCheckInfo" xml:space="preserve">
@@ -76,11 +76,11 @@
<comment>{0} will be replaced by content string. Please note that this string should include newline for formatting.</comment>
</data>
<data name="ErrorConfigPropertyInvalid" xml:space="preserve">
<value>Kohdassa {0} muokattu arvo {1} on epäkelpo</value>
<value>Kohdassa {0} määritelty arvo {1} on virheellinen</value>
<comment>{0} will be replaced by name of the configuration property, {1} will be replaced by invalid value</comment>
</data>
<data name="ErrorEarlyFatalExceptionInfo" xml:space="preserve">
<value>ASF V{0} on törmännyt ylitsepääsemättömään poikkeukseen ennen kuin ytimen lokinkirjaus moduuli ehdittiin käynnistää!</value>
<value>ASF V{0} on törmännyt ylitsepääsemättömään poikkeukseen ennen kuin ytimen lokinkirjausmoduuli ehdittiin käynnistää!</value>
<comment>{0} will be replaced by version number</comment>
</data>
<data name="ErrorEarlyFatalExceptionPrint" xml:space="preserve">
@@ -97,16 +97,18 @@ StackTrace:
<comment>{0} will be replaced by URL of the request</comment>
</data>
<data name="ErrorGlobalConfigNotLoaded" xml:space="preserve">
<value>Yleisiä asetuksia ei voitu ladata. Tarkista että {0} on olemassa ja validi. Seuraa wikin 'setting up' ohjetta mikäli tarvitset apua.</value>
<value>Yleisiä asetuksia ei voitu ladata. Tarkista että {0} on olemassa ja oikein. Seuraa wikin 'setting up' ohjetta mikäli tarvitset apua.</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="ErrorIsInvalid" xml:space="preserve">
<value>{0} on virheellinen!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorNoBotsDefined" xml:space="preserve">
<value>Yhtään bottia ei ole määritelty. Unohditko määrittää ASF:n asetuksesi? Noudata 'Setting up' -opasta wikissä, jos olet hämmentynyt.</value>
</data>
<data name="ErrorObjectIsNull" xml:space="preserve">
<value>{0} on ei mitään!</value>
<value>{0} on tyhjä!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorParsingObject" xml:space="preserve">
@@ -127,7 +129,7 @@ StackTrace:
<value>Päivittämistä ei voitu jatkaa koska kyseinen versio ei sisällä yhtään tiedostoa!</value>
</data>
<data name="ErrorUserInputRunningInHeadlessMode" xml:space="preserve">
<value>Huomasimme tarpeen käyttäjän toimille, mutta prosessi on käynnistetty headless-tilassa!</value>
<value>Vastaanotettiin pyyntö käyttäjän syötteelle, mutta prosessi on käynnistetty headless-tilassa!</value>
</data>
<data name="Exiting" xml:space="preserve">
<value>Suljetaan...</value>
@@ -146,14 +148,14 @@ StackTrace:
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="LoggingIn" xml:space="preserve">
<value>Kirjaudutaan to {0}...</value>
<value>Kirjaudutaan sisään {0}...</value>
<comment>{0} will be replaced by service's name</comment>
</data>
<data name="NoBotsAreRunning" xml:space="preserve">
<value>Yhtään bottia ei ole käynnissä, poistutaan...</value>
</data>
<data name="RefreshingOurSession" xml:space="preserve">
<value>Virkistetään istuntomme!</value>
<value>Päivitetään istuntomme!</value>
</data>
<data name="RejectingTrade" xml:space="preserve">
<value>Hylätään vaihto: {0}</value>
@@ -189,10 +191,13 @@ StackTrace:
<comment>{0} will be replaced by current version, {1} will be replaced by remote version</comment>
</data>
<data name="UserInputSteam2FA" xml:space="preserve">
<value>Syötä 2FA koodi Steam varmennus sovelluksesta: </value>
<value>Syötä 2FA-koodi Steam-varmennussovelluksesta: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamGuard" xml:space="preserve">
<value>Syötä SteamGuard -varmennuskoodi, joka lähetettiin sähköpostiisi: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamLogin" xml:space="preserve">
<value>Syötä Steam-tilisi käyttäjätunnus: </value>
<comment>Please note that this translation should end with space</comment>
@@ -222,43 +227,91 @@ StackTrace:
<value>Bottia nimeltä {0} ei voitu löytää!</value>
<comment>{0} will be replaced by bot's name query (string)</comment>
</data>
<data name="BotStatusOverview" xml:space="preserve">
<value>Tällä hetkellä on käytössä {0}/{1} bottia, joilla on {2} peliä ({3} korttia) jäljellä farmattavaksi.</value>
<comment>{0} will be replaced by number of active bots, {1} will be replaced by total number of bots, {2} will be replaced by total number of games left to farm, {3} will be replaced by total number of cards left to farm</comment>
</data>
<data name="BotStatusIdling" xml:space="preserve">
<value>Botti farmaa peliä: {0} ({1}, {2} korttia jäljellä) jäljellä olevista {3} pelistä ({4} korttia). Farmausta jäljellä: ~{5}.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm, {3} will be replaced by total number of games to farm, {4} will be replaced by total number of cards to farm, {5} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="BotStatusIdlingList" xml:space="preserve">
<value>Botti farmaa pelejä: {0} jäljellä olevista {1} pelistä ({2} korttia). Farmausta jäljellä: ~{3}.</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), {1} will be replaced by total number of games to farm, {2} will be replaced by total number of cards to farm, {3} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="CheckingFirstBadgePage" xml:space="preserve">
<value>Tarkastellaan ensimmäistä badge sivua...</value>
<value>Tarkastellaan ensimmäistä badge-sivua...</value>
</data>
<data name="CheckingOtherBadgePages" xml:space="preserve">
<value>Tarkastellaan muita badge sivuja...</value>
<value>Tarkastellaan muita badge-sivuja...</value>
</data>
<data name="ChosenFarmingAlgorithm" xml:space="preserve">
<value>Valittu farmauksen algoritmi: {0}</value>
<comment>{0} will be replaced by the name of chosen farming algorithm</comment>
</data>
<data name="Done" xml:space="preserve">
<value>Valmis!</value>
</data>
<data name="GamesToIdle" xml:space="preserve">
<value>Farmattavana yhteensä {0} peliä ({1} korttia), ~{2} jäljellä...</value>
<comment>{0} will be replaced by number of games, {1} will be replaced by number of cards, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="IdlingFinished" xml:space="preserve">
<value>Farmaus valmis!</value>
</data>
<data name="IdlingFinishedForGame" xml:space="preserve">
<value>Farmaus valmis: {0} ({1}) Kulunut peliaika: {2}!</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="IdlingFinishedForGames" xml:space="preserve">
<value>Farmaus valmistunut seuraavien pelien osalta: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="IdlingStatusForGame" xml:space="preserve">
<value>Farmattavana {0} ({1}): {2} korttia jäljellä</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm</comment>
</data>
<data name="IdlingStopped" xml:space="preserve">
<value>Farmaus pysäytetty!</value>
</data>
<data name="IgnoredPermanentPauseEnabled" xml:space="preserve">
<value>Tämä pyyntö jätetään huomioimatta, kun pysyvä tauko on päällä!</value>
</data>
<data name="NothingToIdle" xml:space="preserve">
<value>Tällä tilillä ei ole mitään farmattavaa!</value>
</data>
<data name="NowIdling" xml:space="preserve">
<value>Nyt farmataan: {0} ({1})</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="NowIdlingList" xml:space="preserve">
<value>Nyt farmataan: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="PlayingNotAvailable" xml:space="preserve">
<value>Pelaaminen ei ole tällä hetkellä mahdollista, yritetään myöhemmin uudestaan!</value>
</data>
<data name="StillIdling" xml:space="preserve">
<value>Farmataan edelleen: {0} ({1})</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="StillIdlingList" xml:space="preserve">
<value>Farmataan edelleen: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="StoppedIdling" xml:space="preserve">
<value>Farmaus pysäytetty: {0} ({1})</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="StoppedIdlingList" xml:space="preserve">
<value>Farmaus pysäytetty: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="UnknownCommand" xml:space="preserve">
<value>Tuntematon komento!</value>
</data>
<data name="WarningCouldNotCheckBadges" xml:space="preserve">
<value>Merkkien hakeminen epäonnistui, yritetään myöhemmin uudestaan!</value>
<value>Merkkien tietojen hakeminen epäonnistui, yritetään myöhemmin uudestaan!</value>
</data>
<data name="WarningCouldNotCheckCardsStatus" xml:space="preserve">
<value>Ei voitu tarkastaan korttien tilaa kohteelle: {0} ({1}), yritetään myöhemmin uudestaan!</value>
@@ -268,13 +321,15 @@ StackTrace:
<value>Hyväksytään lahjaa: {0}...</value>
<comment>{0} will be replaced by giftID (number)</comment>
</data>
<data name="BotAccountLimited" xml:space="preserve">
<value>Tämä tili on rajoitettu, farmaus ei ole mahdollista ennen kuin rajoitus poistetaan!</value>
</data>
<data name="BotAddLicense" xml:space="preserve">
<value>ID: {0} | Tila: {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by status string</comment>
</data>
<data name="BotAddLicenseWithItems" xml:space="preserve">
<value>ID: {0} | Tila: {1} | Tuotteet: {2}</value>
<value>ID: {0} | Tila: {1} | Tavarat: {2}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by status string, {2} will be replaced by list of granted IDs (numbers), separated by a comma</comment>
</data>
<data name="BotAlreadyRunning" xml:space="preserve">
@@ -284,16 +339,24 @@ StackTrace:
<value>Muutetaan .maFile ASF:n käyttämään muotoon...</value>
</data>
<data name="BotAuthenticatorImportFinished" xml:space="preserve">
<value>Mobiili authentikaattorin tuonti onnistui!</value>
<value>Mobiilivarmentajan tuonti onnistui!</value>
</data>
<data name="BotAuthenticatorToken" xml:space="preserve">
<value>2FA Koodi: {0}</value>
<value>2FA-koodi: {0}</value>
<comment>{0} will be replaced by generated 2FA token (string)</comment>
</data>
<data name="BotAutomaticIdlingNowPaused" xml:space="preserve">
<value>Automattinen farmaus on pysäytetty!</value>
</data>
<data name="BotAutomaticIdlingNowResumed" xml:space="preserve">
<value>Automaattista farmausta on jatkettu!</value>
</data>
<data name="BotAutomaticIdlingPausedAlready" xml:space="preserve">
<value>Automattinen farmaus on jo pysäytetty!</value>
</data>
<data name="BotAutomaticIdlingResumedAlready" xml:space="preserve">
<value>Automattista farmausta on jo jatkettu!</value>
</data>
<data name="BotConnected" xml:space="preserve">
<value>Yhdistetty Steamiin!</value>
</data>
@@ -304,7 +367,7 @@ StackTrace:
<value>Katkaistaan yhteyttä...</value>
</data>
<data name="BotInstanceNotStartingBecauseDisabled" xml:space="preserve">
<value>Ei käynnistetä tätä bottia koska se on poistettu käytöstä configuraatiossa!</value>
<value>Ei käynnistetä tätä bottia koska se on poistettu käytöstä asetustiedostossa!</value>
</data>
<data name="BotInvalidAuthenticatorDuringLogin" xml:space="preserve">
<value>Saimme TwoFactorCodeMismatch virhekoodin {0} kertaa putkeen. Joko 2FA tilitiedot eivät ole enää voimassa, tai kellosi ei ole synkronoitu, keskeytetään!</value>
@@ -322,33 +385,38 @@ StackTrace:
<value>Kirjaudutaan sisään...</value>
</data>
<data name="BotLogonSessionReplaced" xml:space="preserve">
<value>Tämä käyttäjä vaikuttaisi olevan käytössä toisessa ASF instanssissa. Tällaista käyttäytymistä ei ole määritelty, kieltäydytään suorittamasta!</value>
<value>Tämä käyttäjä vaikuttaisi olevan käytössä toisessa ASF-instanssissa. Tällaista käyttäytymistä ei ole määritelty, kieltäydytään suorittamasta!</value>
</data>
<data name="BotLootingFailed" xml:space="preserve">
<value>Vaihtotarjous epäonnistui!</value>
</data>
<data name="BotLootingMasterNotDefined" xml:space="preserve">
<value>Vaihtoa ei voitu lähettää koska yhtään käyttäjää master-oikeuksilla ei ole määritelty!</value>
<value>Vaihtoa ei voitu lähettää koska yhtään käyttäjää pääkäyttöoikeuksilla ei ole määritelty!</value>
</data>
<data name="BotLootingSuccess" xml:space="preserve">
<value>Vaihtopyyntö lähetetty onnistuneesti!</value>
</data>
<data name="BotSendingTradeToYourself" xml:space="preserve">
<value>Et voi tehdä vaihtokauppaa itsesi kanssa!</value>
</data>
<data name="BotNoASFAuthenticator" xml:space="preserve">
<value>Tällä botilla ei ole ASF 2FA käytössä! Unohditko ottaa ASF 2FA authentikaattorin käyttöön?</value>
<value>Tällä botilla ei ole ASF 2FA-käytössä! Unohditko ottaa ASF 2FA-varmennuksen käyttöön?</value>
</data>
<data name="BotNotConnected" xml:space="preserve">
<value>Tämä botti instanssi ei ole yhdistettynä!</value>
</data>
<data name="BotNotOwnedYet" xml:space="preserve">
<value>Omistamattomat: {0}</value>
<value>Ei vielä omistettu: {0}</value>
<comment>{0} will be replaced by query (string)</comment>
</data>
<data name="BotOwnedAlreadyWithName" xml:space="preserve">
<value>Omistetut {0} | {1}</value>
<value>Jo omistetut {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotPointsBalance" xml:space="preserve">
<value>Pistesaldo: {0}</value>
<comment>{0} will be replaced by the points balance value (integer)</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>Yritysmäärä on ylitetty, yritetään uudelleen {0} jälkeen...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
@@ -367,8 +435,12 @@ StackTrace:
<data name="BotRemovedExpiredLoginKey" xml:space="preserve">
<value>Poistettu vanhentunut kirjautumisavain!</value>
</data>
<data name="BotStatusNotIdling" xml:space="preserve">
<value>Botti ei farmaa mitään.</value>
</data>
<data name="BotStatusLimited" xml:space="preserve">
<value>Botti on rajoitettu eikä tämän takia voi saada yhtään korttia farmaamalla.</value>
</data>
<data name="BotStatusConnecting" xml:space="preserve">
<value>Botti yhdistää Steam-verkkoon.</value>
</data>
@@ -400,8 +472,12 @@ StackTrace:
<data name="BotConnectionLost" xml:space="preserve">
<value>Yhteys Steam-verkkoon katkesi. Yhdistetään uudelleen...</value>
</data>
<data name="BotAccountFree" xml:space="preserve">
<value>Tili ei ole enää varattu: farmausta jatketaan!</value>
</data>
<data name="BotAccountOccupied" xml:space="preserve">
<value>Tiliä käytetään tällä hetkellä muualla: ASF jatkaa farmaamista kun tili vapautuu...</value>
</data>
<data name="BotConnecting" xml:space="preserve">
<value>Yhdistetään...</value>
</data>
@@ -435,8 +511,14 @@ StackTrace:
<data name="ErrorInvalidCurrentCulture" xml:space="preserve">
<value>Antamasi CurrentCulture on epäkelpo, ASF jatkaa toimintaa oletusarvolla!</value>
</data>
<data name="TranslationIncomplete" xml:space="preserve">
<value>ASF koettaa käyttää haluttua lokalisaatiota ({0}), mutta käännös tällä kielellä on vain {1} valmis. Ehkä voisit auttaa meitä parantamaan ASF:n käännöstä omalle kielellesi?</value>
<comment>{0} will be replaced by culture code, such as "en-US", {1} will be replaced by completeness percentage, such as "78.5%"</comment>
</data>
<data name="IdlingGameNotPossible" xml:space="preserve">
<value>Pelin {0} ({1}) farmaus on väliaikaisesti poistettu käytöstä, koska ASF ei pysty pelaamaan tätä peliä tällä hetkellä.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningIdlingGameMismatch" xml:space="preserve">
<value>ASF huomasi ID poikkeavuuden kohteessa {0} ({1}) ja käyttää ID:tä {2} tämän sijaan.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by game's ID (number)</comment>
@@ -445,8 +527,12 @@ StackTrace:
<value>{0} V{1}</value>
<comment>{0} will be replaced by program's name (e.g. "ASF"), {1} will be replaced by program's version (e.g. "1.0.0.0"). This string typically has nothing to translate and you should leave it as it is, unless you need to change the format, e.g. in RTL languages.</comment>
</data>
<data name="BotAccountLocked" xml:space="preserve">
<value>Tämä tili on lukittu, farmaus on pysyvästi pois käytöstä!</value>
</data>
<data name="BotStatusLocked" xml:space="preserve">
<value>Botti on lukittu, eikä voi tämän takia saada yhtään korttia farmaamalla.</value>
</data>
<data name="ErrorFunctionOnlyInHeadlessMode" xml:space="preserve">
<value>Tämä funktio on käytettävissä vain headless-tilassa!</value>
</data>
@@ -457,8 +543,14 @@ StackTrace:
<data name="ErrorAccessDenied" xml:space="preserve">
<value>Pääsy kielletty!</value>
</data>
<data name="WarningPreReleaseVersion" xml:space="preserve">
<value>Käytät versiota joka on uudempi kuin uusin julkaistu versio käyttämälläsi päivityskanavalla. Huomoithan että esijulkaistut versiot ovat tarkoitettu käyttäjille, jotka osaavat raportoida virheistä, selviävät ongelmien kanssa sekä antavat palautetta - teknistä tukea ei anneta.</value>
</data>
<data name="BotStats" xml:space="preserve">
<value>Nykyinen muistinkäyttö: {0} MB.
Prosessin käyttöaika: {1}</value>
<comment>{0} will be replaced by number (in megabytes) of memory being used, {1} will be replaced by translated TimeSpan string (such as "25 minutes"). Please note that this string should include newlines for formatting.</comment>
</data>
<data name="ClearingDiscoveryQueue" xml:space="preserve">
<value>Tyhjennetään Steamin discovery-jonoa #{0}...</value>
<comment>{0} will be replaced by queue number</comment>
@@ -530,7 +622,9 @@ StackTrace:
<data name="NothingFound" xml:space="preserve">
<value>Mitään ei löytynyt!</value>
</data>
<data name="PluginsWarning" xml:space="preserve">
<value>Olet ladannut yhden tai useamman mukautetun lisäosan ASF: ään. Koska emme pysty tarjoamaan tukea modatuille ympäristöille, ole hyvä ja käänny ongelmien ilmetessä käyttöönottamiesi lisäosien tekijöiden puoleen.</value>
</data>
<data name="PleaseWait" xml:space="preserve">
<value>Odota hetki...</value>
</data>
@@ -550,8 +644,14 @@ StackTrace:
<data name="ErrorSingleInstanceRequired" xml:space="preserve">
<value>ASF prosessi on jo käynnissä tässä työhakemistossa. Keskeytetään!</value>
</data>
<data name="BotHandledConfirmations" xml:space="preserve">
<value>Onnistuneesti käsiteltiin {0} vahvistusta!</value>
<comment>{0} will be replaced by number of confirmations</comment>
</data>
<data name="BotExtraIdlingCooldown" xml:space="preserve">
<value>Odotetaan enintään {0} varmistaaksemme, että olemme vapaita aloittamaan farmauksen...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "1 minute")</comment>
</data>
<data name="UpdateCleanup" xml:space="preserve">
<value>Siivotaan vanhat tiedostot päivityksen jälkeen...</value>
</data>
@@ -561,25 +661,79 @@ StackTrace:
<data name="IPCConfigChanged" xml:space="preserve">
<value>IPC asetusta on muutettu!</value>
</data>
<data name="BotTradeOfferResult" xml:space="preserve">
<value>Vaihtotarjous {0} on tilassa {1} syystä {2}.</value>
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
</data>
<data name="BotInvalidPasswordDuringLogin" xml:space="preserve">
<value>Vastaanotettu invalidPassword -virhekoodi {0} kertaa peräkkäin. Salasanasi tälle tilille on todennäköisesti väärin, keskeytetään!</value>
<comment>{0} will be replaced by maximum allowed number of failed login attempts</comment>
</data>
<data name="Result" xml:space="preserve">
<value>Tulos: {0}</value>
<comment>{0} will be replaced by generic result of various functions that use this string</comment>
</data>
<data name="WarningUnsupportedEnvironment" xml:space="preserve">
<value>Yrität suorittaa ASF:n {0} varianttia ympäristössä jota ei tueta: {1}. Lisää --ignore-unsupported-environment -argumentti, jos todella tiedät mitä olet tekemässä.</value>
</data>
<data name="WarningUnknownCommandLineArgument" xml:space="preserve">
<value>Tuntematon komentorivin argumentti: {0}</value>
<comment>{0} will be replaced by unrecognized command that has been provided</comment>
</data>
<data name="ErrorConfigDirectoryNotFound" xml:space="preserve">
<value>Asetushakemistoa ei kyetty löytämään, keskeytetään!</value>
</data>
<data name="BotIdlingSelectedGames" xml:space="preserve">
<value>Pelataan valittuja {0}: {1}</value>
<comment>{0} will be replaced by internal name of the config property (e.g. "GamesPlayedWhileIdle"), {1} will be replaced by comma-separated list of appIDs that user has chosen</comment>
</data>
<data name="AutomaticFileMigration" xml:space="preserve">
<value>{0} asetustiedosto muutetaan uusimpaan syntaksiin...</value>
<comment>{0} will be replaced with the relative path to the affected config file</comment>
</data>
<data name="WarningWeakIPCPassword" xml:space="preserve">
<value>IPC-salasanasi näyttää olevan heikko. Harkitse vahvemman salasanan valitsemista turvallisuuden parantamiseksi. Yksityiskohdat: {0}</value>
<comment>{0} will be replaced by additional details about the password being considered weak</comment>
</data>
<data name="WarningWeakSteamPassword" xml:space="preserve">
<value>Steam-salasanasi '{0}' näyttää olevan heikko. Harkitse vahvemman salasanan valitsemista turvallisuuden lisäämiseksi. Yksityiskohdat: {1}</value>
<comment>{0} will be replaced by the affected bot name, {1} will be replaced by additional details about the password being considered weak</comment>
</data>
<data name="WarningWeakCryptKey" xml:space="preserve">
<value>Salausavaimesi näyttää olevan heikko. Harkitse vahvemman valintaa turvallisuuden parantamiseksi. Yksityiskohdat: {0}</value>
<comment>{0} will be replaced by additional details about the encryption key being considered weak</comment>
</data>
<data name="WarningTooShortCryptKey" xml:space="preserve">
<value>Salausavaimesi on liian lyhyt. Suosittelemme käyttämään salausavainta, joka on vähintään {0} tavua (merkkiä) pitkä.</value>
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
<value>Käytät ominaisuuden {1} asetusta {0}, mutta et antanut mukautettua --cryptkey -argumenttia. Sinun pitäisi antaa mukautettu --cryptkey lisäturvallisuuden takaamiseksi.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "SCrypt"), {1} will be replaced by the name of the property (e.g. "IPCPassword")</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForEncryption" xml:space="preserve">
<value>Käytät ominaisuuden {1} asetusta {0}, mutta et antanut mukautettua --cryptkey -argumenttia. Tämä tekee suojauksen täysin tyhjäksi, koska ASF joutuu käyttämään omaa (tunnettua) avaintaan. Sinun tulisi antaa mukautettu --cryptkey tämän asetuksen turvallisuushyöydyn saavuttamiseksi.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>
</data>
<data name="WarningRunningAsRoot" xml:space="preserve">
<value>Yrität käynnistää ASF:ää järjestelmänvalvojana (root). Tämä aiheuttaa merkittävän turvallisuusriskin koneellesi ja koska ASF ei tarvitse pääkäyttäjän oikeuksia toimintaansa, suosittelemme käyttämään sitä ei-järjestelmänvalvojan tunnuksilla, jos mahdollista.</value>
</data>
<data name="WarningRunningInUnsupportedEnvironment" xml:space="preserve">
<value>Käytössäsi on ASF tukemattomassa ympäristössä, käyttäen --ignore-unsupported-environment argumenttia. Huomioithan, että emme tarjoa minkäänlaista tukea tälle skenaariolle ja teet sen täysin omalla vastuullasi. Sinua on varoitettu.</value>
</data>
<data name="FetchingChecksumFromRemoteServer" xml:space="preserve">
<value>Haetaan tarkistussummaa etäpalvelimelta...</value>
</data>
<data name="VerifyingChecksumWithRemoteServer" xml:space="preserve">
<value>Tarkistetaan ladatun binäärin tarkistussummaa etäpalvelimelta saatuun...</value>
</data>
<data name="ChecksumMissing" xml:space="preserve">
<value>Etäpalvelin ei tiedä mitään julkaisusta, johon olemme päivittämässä. Tämä tilanne on mahdollinen, jos julkistaminen on hiljattain julkaistu - kieltäydytään jatkamasta päivitystä ylimääräisenä turvatoimenpiteenä.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>Etäpalvelin on vastannut eri tarkistussummalla, mikä saattaa merkitä viallista latausta tai MITM-hyökkäystä, kieltäydytään jatkamasta päivitystä!</value>
</data>
<data name="PatchingFiles" xml:space="preserve">
<value>Paikataan ASF-tiedostoja...</value>
</data>
</root>

View File

@@ -129,7 +129,7 @@ StackTrace:
<value>Não foi possível prosseguir com uma atualização, pois essa versão não inclui nenhum recurso!</value>
</data>
<data name="ErrorUserInputRunningInHeadlessMode" xml:space="preserve">
<value>Solitação para input do utilizador foi recebida mas o processo está a ser executado em modo 'headless'!</value>
<value>Solicitação para entrada do utilizador foi recebida, mas o processo está a ser executado em modo 'headless'!</value>
</data>
<data name="Exiting" xml:space="preserve">
<value>A sair...</value>

View File

@@ -63,11 +63,11 @@
</value>
</resheader>
<data name="AcceptingTrade" xml:space="preserve">
<value>Onaylanan takas: {0}</value>
<value>Takas onaylanıyor: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="AutoUpdateCheckInfo" xml:space="preserve">
<value>ASF, her {0} zaman aralığında yeni sürümleri kontrol edecektir.</value>
<value>ASF, her {0} sonra yeni sürümleri kontrol edecektir.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "24 hours")</comment>
</data>
<data name="Content" xml:space="preserve">
@@ -80,12 +80,12 @@
<comment>{0} will be replaced by name of the configuration property, {1} will be replaced by invalid value</comment>
</data>
<data name="ErrorEarlyFatalExceptionInfo" xml:space="preserve">
<value>ASF v{0}, çekirdek kayıt günlüğü modülü başlatılmadan önce kritik bir hata ile karşılaştı!</value>
<value>ASF v{0}, çekirdek kayıt günlüğü modülü bile başlatılamadan önce kritik bir hata ile karşılaştı!</value>
<comment>{0} will be replaced by version number</comment>
</data>
<data name="ErrorEarlyFatalExceptionPrint" xml:space="preserve">
<value>İstisna: {0}() {1}
Yığın izleme:
Yığın Kaydı:
{2}</value>
<comment>{0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting.</comment>
</data>
@@ -105,7 +105,7 @@ Yığın izleme:
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorNoBotsDefined" xml:space="preserve">
<value>Tanımlanmış bot yok. ASF'yi yapılandırmayı unuttunuz mu? Kafası karıştıysa wiki'deki 'setting up / kurulum' rehberine bakın.</value>
<value>Tanımlanmış bot yok. ASF'yi yapılandırmayı unuttunuz mu? Kafanız karıştıysa wiki'deki 'setting up / kurulum' rehberine bakın.</value>
</data>
<data name="ErrorObjectIsNull" xml:space="preserve">
<value>{0} boş!</value>
@@ -144,7 +144,7 @@ Yığın izleme:
<value>Genel yapılandırma dosyası kaldırıldı!</value>
</data>
<data name="IgnoringTrade" xml:space="preserve">
<value>Yoksayılan takas: {0}</value>
<value>Takas yoksayılıyor: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="LoggingIn" xml:space="preserve">
@@ -177,7 +177,7 @@ Yığın izleme:
<value>Yeni sürüm kontrol ediliyor...</value>
</data>
<data name="UpdateDownloadingNewVersion" xml:space="preserve">
<value>Yeni sürüm indiriliyor: {0} ({1} MB)... Beklerken, yaptığımız çalışmayı takdir ediyorsanız bağış yapmayı düşünün! :)</value>
<value>Yeni sürüm indiriliyor: {0} ({1} MB)... Beklerken, yaptığımız çalışmayı takdir ediyorsanız bağış yapabilirsiniz! :)</value>
<comment>{0} will be replaced by version string, {1} will be replaced by update size (in megabytes)</comment>
</data>
<data name="UpdateFinished" xml:space="preserve">
@@ -314,11 +314,11 @@ Yığın izleme:
<value>Rozet bilgisi alınamadı, daha sonra tekrar deneyeceğiz!</value>
</data>
<data name="WarningCouldNotCheckCardsStatus" xml:space="preserve">
<value>{0} ({1}) için kartların durumunu kontrol edemedik, daha sonra tekrar deneyelim!</value>
<value>{0} ({1}) için kartların durumunu kontrol edemedik, daha sonra tekrar deneyeceğiz!</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotAcceptingGift" xml:space="preserve">
<value>Kabul edilen hediye: {0}...</value>
<value>Hediye kabul ediliyor: {0}...</value>
<comment>{0} will be replaced by giftID (number)</comment>
</data>
<data name="BotAccountLimited" xml:space="preserve">
@@ -370,7 +370,7 @@ Yığın izleme:
<value>Bu bot örneği, yapılandırma dosyasında devre dışı bırakıldığından başlatılmıyor!</value>
</data>
<data name="BotInvalidAuthenticatorDuringLogin" xml:space="preserve">
<value>Üst üste {0} kez İki Adımlı Doğrulama Kodunuz (TwoFactorCodeMismatch) hataya uğradı. Ya 2AD kodlarınız artık geçerli değil ya da saatiniz eşitlenmemiş, iptal ediliyor!</value>
<value>Üst üste {0} kez 2AD Kodu Uyuşmazlığı hata kodu alındı (TwoFactorCodeMismatch). Ya 2AD kodlarınız artık geçerli değil ya da cihazınızın saati yanlış, iptal ediliyor!</value>
<comment>{0} will be replaced by maximum allowed number of failed 2FA attempts</comment>
</data>
<data name="BotLoggedOff" xml:space="preserve">
@@ -385,7 +385,7 @@ Yığın izleme:
<value>Giriş yapılıyor...</value>
</data>
<data name="BotLogonSessionReplaced" xml:space="preserve">
<value>Bu hesap, çalışmaya devam etmeyi reddeden, tanımlanmamış bir davranış olan başka bir ASF örneğinde kullanılmak üzere görünüyor!</value>
<value>Bu hesap başka bir ASF işleminde kullanılıyor gibi gözüküyor ve ASF bu durumda ne yapacağını bilmiyor, o yüzden başlatılamıyor!</value>
</data>
<data name="BotLootingFailed" xml:space="preserve">
<value>Takas teklifi başarısız oldu!</value>
@@ -406,11 +406,11 @@ Yığın izleme:
<value>Bu bot bağlı değil!</value>
</data>
<data name="BotNotOwnedYet" xml:space="preserve">
<value>Henüz sahip olunmayan: {0}</value>
<value>Henüz buna sahip değil: {0}</value>
<comment>{0} will be replaced by query (string)</comment>
</data>
<data name="BotOwnedAlreadyWithName" xml:space="preserve">
<value>Zaten sahip olunan: {0} | {1}</value>
<value>Zaten buna sahip: {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotPointsBalance" xml:space="preserve">
@@ -418,7 +418,7 @@ Yığın izleme:
<comment>{0} will be replaced by the points balance value (integer)</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>Hız sınırııldı, {0} bekledikten sonra yeniden deneyeceğiz...</value>
<value>İstek sınırııldı, {0} bekledikten sonra yeniden deneyeceğiz...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
@@ -482,7 +482,7 @@ Yığın izleme:
<value>Bağlanılıyor...</value>
</data>
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>İstemcinin bağlantısını kesmek başarısız oldu. Bu bot örneği terk ediliyor!</value>
<value>İstemcinin bağlantısı kesilemedi. Bu bot örneği terk ediliyor!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>SteamDirectory başlatılamadı, Steam Ağı ile bağlantı kurmak her zamankinden daha uzun sürebilir!</value>
@@ -520,7 +520,7 @@ Yığın izleme:
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningIdlingGameMismatch" xml:space="preserve">
<value>ASF {0} ({1}) için bir uyumsuzluk tespit etti ve bunun yerine ID {2} kullanılacak.</value>
<value>ASF {0} ({1}) için bir uyumsuzluk tespit etti ve bunun yerine {2} ID'si kullanılacak.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by game's ID (number)</comment>
</data>
<data name="BotVersion" xml:space="preserve">
@@ -537,14 +537,14 @@ Yığın izleme:
<value>Bu işlev yalnızca headless modda kullanılabilir!</value>
</data>
<data name="BotOwnedAlready" xml:space="preserve">
<value>Zaten sahip olunan: {0}</value>
<value>Zaten buna sahip: {0}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="ErrorAccessDenied" xml:space="preserve">
<value>Erişim reddedildi!</value>
</data>
<data name="WarningPreReleaseVersion" xml:space="preserve">
<value>Güncelleme kanalınız için yayınlanmış en son sürümden daha yeni bir sürüm kullanıyorsunuz. Lütfen ön yayın sürümlerinin, hata raporlamayı, sorunlarla başa çıkmayı ve geribildirim yapmayı bilen kişiler için olduğunu unutmayın. Teknik destek verilmeyecektir.</value>
<value>Güncelleme kanalınız için yayınlanmış en son sürümden daha yeni bir sürüm kullanıyorsunuz. Lütfen ön yayın sürümlerinin, hata raporlamayı, sorunlarla başa çıkmayı ve geribildirim yapmayı bilen kişiler için olduğunu unutmayın - teknik destek verilmeyecektir.</value>
</data>
<data name="BotStats" xml:space="preserve">
<value>Geçerli bellek kullanımı: {0} MB.
@@ -556,7 +556,7 @@ Süreç çalışma zamanı: {1}</value>
<comment>{0} will be replaced by queue number</comment>
</data>
<data name="DoneClearingDiscoveryQueue" xml:space="preserve">
<value>Steam keşif kuyruğu #{0} temizlenmesi bitti.</value>
<value>Steam keşif kuyruğu #{0} temizlendi.</value>
<comment>{0} will be replaced by queue number</comment>
</data>
<data name="BotOwnsOverviewPerGame" xml:space="preserve">
@@ -571,7 +571,7 @@ Süreç çalışma zamanı: {1}</value>
<comment>{0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property)</comment>
</data>
<data name="BotAcceptedDonationTrade" xml:space="preserve">
<value>Kabul edilen takas bağışı: {0}</value>
<value>Kaılıksız takas kabul edildi: {0}</value>
<comment>{0} will be replaced by trade's ID (number)</comment>
</data>
<data name="WarningWorkaroundTriggered" xml:space="preserve">
@@ -645,7 +645,7 @@ Süreç çalışma zamanı: {1}</value>
<value>ASF süreci, zaten bu dizinde çalıştığından iptal ediliyor!</value>
</data>
<data name="BotHandledConfirmations" xml:space="preserve">
<value>{0} onaylama başarıyla ele alındı!</value>
<value>{0} onaylama başarıyla sonuçlandırıldı!</value>
<comment>{0} will be replaced by number of confirmations</comment>
</data>
<data name="BotExtraIdlingCooldown" xml:space="preserve">
@@ -666,7 +666,7 @@ Süreç çalışma zamanı: {1}</value>
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
</data>
<data name="BotInvalidPasswordDuringLogin" xml:space="preserve">
<value>Arka arkaya {0} kere InvalidPassword hata kodu alındı. Bu hesap için parolanız muhtemelen yanlış, iptal ediliyor!</value>
<value>Arka arkaya {0} kere Yanlış Şifre hata kodu alındı (InvalidPassword). Bu hesap için parolanız muhtemelen yanlış, iptal ediliyor!</value>
<comment>{0} will be replaced by maximum allowed number of failed login attempts</comment>
</data>
<data name="Result" xml:space="preserve">
@@ -677,7 +677,7 @@ Süreç çalışma zamanı: {1}</value>
<value>Desteklenmeyen ortamda {0} ASF varyantını çalıştırmaya çalışıyorsun: {1}. Ne yaptığınızı gerçekten biliyorsan, --ignore-unsupported-environment argümanını sağla.</value>
</data>
<data name="WarningUnknownCommandLineArgument" xml:space="preserve">
<value>Bilinmeyen komut satırı bağımsız değişkeni: {0}</value>
<value>Bilinmeyen komut satırı argümanı: {0}</value>
<comment>{0} will be replaced by unrecognized command that has been provided</comment>
</data>
<data name="ErrorConfigDirectoryNotFound" xml:space="preserve">
@@ -716,7 +716,7 @@ Süreç çalışma zamanı: {1}</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>
</data>
<data name="WarningRunningAsRoot" xml:space="preserve">
<value>ASF'yi yönetici (root) olarak çalıştırmaya çalışıyorsunuz. Bu, makineniz için önemli bir güvenlik riskine neden olur ve ASF'nin çalışması için kök erişimi gerektirmez. Mümkünse yönetici olmadan çalıştırmanızı öneriyoruz.</value>
<value>ASF'yi yönetici (root) olarak çalıştırmaya çalışıyorsunuz. Bu, makineniz için önemli bir güvenlik riskine neden olur ve ASF'nin çalışması için yönetici izni gerekmediği için mümkünse yönetici olmadan çalıştırmanızı öneriyoruz.</value>
</data>
<data name="WarningRunningInUnsupportedEnvironment" xml:space="preserve">
<value>ASF'yi desteklenmeyen ortamda çalıştırıyorsunuz ve --ignore-unsupported-environment argümanı sağlıyorsunuz. Lütfen bu senaryo için herhangi bir destek sağlamadığımızı ve bunu tamamen kendi sorumluluğunuzda yaptığınızı unutmayın. Uyarıldınız.</value>
@@ -731,9 +731,9 @@ Süreç çalışma zamanı: {1}</value>
<value>Uzak sunucu, güncelleme yaptığımız sürüm hakkında hiçbir şey bilmiyor. Bu durum, sürüm yakın zamanda yayınlandıysa mümkündür - ek bir güvenlik önlemi olarak güncelleme prosedürüne hemen devam etmeyi reddeder.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>Uzak sunucu farklı bir sağlama toplamı ile yanıt verdi, bu, güncelleme prosedürüne devam etmeyi reddeden bozuk indirme veya MITM saldırısını gösterebilir!</value>
<value>Uzak sunucu farklı bir sağlama sayısı ile yanıt verdi, bu güncelleme dosyalarının bozuk indiğine veya MITM saldırısına işaret olabilir, güncelleme durduruluyor!</value>
</data>
<data name="PatchingFiles" xml:space="preserve">
<value>ASF dosyaları yamanıyor...</value>
<value>ASF dosyaları yamalanıyor...</value>
</data>
</root>

View File

@@ -50,6 +50,10 @@ public sealed class ArchiLogger {
throw new ArgumentNullException(nameof(message));
}
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
Logger.Debug($"{previousMethodName}() {message}");
}
@@ -57,6 +61,10 @@ public sealed class ArchiLogger {
public void LogGenericDebuggingException(Exception exception, [CallerMemberName] string? previousMethodName = null) {
ArgumentNullException.ThrowIfNull(exception);
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
if (!Debugging.IsUserDebugging) {
return;
}
@@ -70,6 +78,10 @@ public sealed class ArchiLogger {
throw new ArgumentNullException(nameof(message));
}
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
Logger.Error($"{previousMethodName}() {message}");
}
@@ -77,6 +89,10 @@ public sealed class ArchiLogger {
public void LogGenericException(Exception exception, [CallerMemberName] string? previousMethodName = null) {
ArgumentNullException.ThrowIfNull(exception);
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
Logger.Error(exception, $"{previousMethodName}()");
}
@@ -86,6 +102,10 @@ public sealed class ArchiLogger {
throw new ArgumentNullException(nameof(message));
}
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
Logger.Info($"{previousMethodName}() {message}");
}
@@ -95,6 +115,10 @@ public sealed class ArchiLogger {
throw new ArgumentNullException(nameof(message));
}
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
Logger.Trace($"{previousMethodName}() {message}");
}
@@ -104,6 +128,10 @@ public sealed class ArchiLogger {
throw new ArgumentNullException(nameof(message));
}
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
Logger.Warn($"{previousMethodName}() {message}");
}
@@ -111,6 +139,10 @@ public sealed class ArchiLogger {
public void LogGenericWarningException(Exception exception, [CallerMemberName] string? previousMethodName = null) {
ArgumentNullException.ThrowIfNull(exception);
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
Logger.Warn(exception, $"{previousMethodName}()");
}
@@ -120,6 +152,10 @@ public sealed class ArchiLogger {
throw new ArgumentNullException(nameof(nullObjectName));
}
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nullObjectName), previousMethodName);
}
@@ -128,6 +164,10 @@ public sealed class ArchiLogger {
throw new ArgumentNullException(nameof(message));
}
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
if (((chatGroupID == 0) || (chatID == 0)) && (steamID == 0)) {
throw new InvalidOperationException($"(({nameof(chatGroupID)} || {nameof(chatID)}) && {nameof(steamID)})");
}
@@ -160,6 +200,10 @@ public sealed class ArchiLogger {
internal async Task LogFatalException(Exception exception, [CallerMemberName] string? previousMethodName = null) {
ArgumentNullException.ThrowIfNull(exception);
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
Logger.Fatal(exception, $"{previousMethodName}()");
// If LogManager has been initialized already, don't do anything else
@@ -212,6 +256,10 @@ public sealed class ArchiLogger {
throw new ArgumentOutOfRangeException(nameof(steamID));
}
if (string.IsNullOrEmpty(previousMethodName)) {
throw new ArgumentNullException(nameof(previousMethodName));
}
ulong steamID64 = steamID;
string loggedMessage = $"{previousMethodName}() {steamID.AccountType} {steamID64}{(handled.HasValue ? $" = {handled.Value}" : "")}";

View File

@@ -179,7 +179,6 @@ internal static class Logging {
ArchiveNumbering = ArchiveNumberingMode.Rolling,
ArchiveOldFileOnStartup = true,
CleanupFileName = false,
ConcurrentWrites = false,
DeleteOldFileOnStartup = true,
FileName = Path.Combine("${currentdir}", SharedInfo.LogFile),
Layout = GeneralLayout,
@@ -187,8 +186,7 @@ internal static class Logging {
};
#pragma warning restore CA2000 // False positive, we're adding this disposable object to the global scope, so we can't dispose it
LogManager.Configuration.AddTarget(fileTarget);
LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, fileTarget));
InitializeTarget(LogManager.Configuration, fileTarget);
LogManager.ReconfigExistingLoggers();
}
@@ -211,8 +209,7 @@ internal static class Logging {
ColoredConsoleTarget coloredConsoleTarget = new("ColoredConsole") { Layout = GeneralLayout };
#pragma warning restore CA2000 // False positive, we're adding this disposable object to the global scope, so we can't dispose it
config.AddTarget(coloredConsoleTarget);
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, coloredConsoleTarget));
InitializeTarget(config, coloredConsoleTarget);
LogManager.Configuration = config;
}
@@ -230,8 +227,7 @@ internal static class Logging {
MaxCount = 20
};
LogManager.Configuration.AddTarget(historyTarget);
LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, historyTarget));
InitializeTarget(LogManager.Configuration, historyTarget);
LogManager.ReconfigExistingLoggers();
}
@@ -315,6 +311,8 @@ internal static class Logging {
while (!Program.ShutdownSequenceInitialized) {
try {
if (IsWaitingForUserInput || !Console.KeyAvailable) {
await Task.Delay(ConsoleResponsivenessDelay).ConfigureAwait(false);
continue;
}
@@ -383,8 +381,6 @@ internal static class Logging {
ASF.ArchiLogger.LogGenericException(e);
return;
} finally {
await Task.Delay(ConsoleResponsivenessDelay).ConfigureAwait(false);
}
}
}
@@ -397,6 +393,22 @@ internal static class Logging {
}
}
private static void InitializeTarget(LoggingConfiguration config, Target target) {
ArgumentNullException.ThrowIfNull(config);
ArgumentNullException.ThrowIfNull(target);
config.AddTarget(target);
if (!Debugging.IsUserDebugging) {
// Silence default ASP.NET logging
config.LoggingRules.Add(new LoggingRule("Microsoft*", target) { FinalMinLevel = LogLevel.Warn });
config.LoggingRules.Add(new LoggingRule("Microsoft.Hosting.Lifetime*", target) { FinalMinLevel = LogLevel.Info });
config.LoggingRules.Add(new LoggingRule("System*", target) { FinalMinLevel = LogLevel.Warn });
}
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, target));
}
private static void OnConfigurationChanged(object? sender, LoggingConfigurationChangedEventArgs e) {
ArgumentNullException.ThrowIfNull(e);

View File

@@ -61,7 +61,7 @@ internal sealed class SteamTarget : AsyncTaskTarget {
protected override async Task WriteAsyncTask(LogEventInfo logEvent, CancellationToken cancellationToken) {
ArgumentNullException.ThrowIfNull(logEvent);
base.Write(logEvent);
Write(logEvent);
if ((SteamID == 0) || (Bot.Bots == null) || Bot.Bots.IsEmpty) {
return;

View File

@@ -476,10 +476,7 @@ internal static class Program {
private static async void OnUnhandledException(object? sender, UnhandledExceptionEventArgs e) {
ArgumentNullException.ThrowIfNull(e);
if (e.ExceptionObject == null) {
throw new ArgumentNullException(nameof(e));
}
ArgumentNullException.ThrowIfNull(e.ExceptionObject);
await ASF.ArchiLogger.LogFatalException((Exception) e.ExceptionObject).ConfigureAwait(false);
await Exit(1).ConfigureAwait(false);
@@ -487,10 +484,7 @@ internal static class Program {
private static async void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e) {
ArgumentNullException.ThrowIfNull(e);
if (e.Exception == null) {
throw new ArgumentNullException(nameof(e));
}
ArgumentNullException.ThrowIfNull(e.Exception);
await ASF.ArchiLogger.LogFatalException(e.Exception).ConfigureAwait(false);

View File

@@ -65,8 +65,7 @@ public sealed class Bot : IAsyncDisposable {
private const char DefaultBackgroundKeysRedeemerSeparator = '\t';
private const byte LoginCooldownInMinutes = 25; // Captcha disappears after around 20 minutes, so we make it 25
private const uint LoginID = 1242; // This must be the same for all ASF bots and all ASF processes
private const byte MaxInvalidPasswordFailures = WebBrowser.MaxTries; // Max InvalidPassword failures in a row before we determine that our password is invalid (because Steam wrongly returns those, of course)
private const byte MaxTwoFactorCodeFailures = WebBrowser.MaxTries; // Max TwoFactorCodeMismatch failures in a row before we determine that our 2FA credentials are invalid (because Steam wrongly returns those, of course)
private const byte MaxLoginFailures = WebBrowser.MaxTries; // Max login failures in a row before we determine that our credentials are invalid (because Steam wrongly returns those, of course)course)
private const byte RedeemCooldownInHours = 1; // 1 hour since first redeem attempt, this is a limitation enforced by Steam
[PublicAPI]
@@ -238,10 +237,10 @@ public sealed class Bot : IAsyncDisposable {
#pragma warning restore CA2213 // False positive, .NET Framework can't understand DisposeAsync()
private byte HeartBeatFailures;
private byte InvalidPasswordFailures;
private EResult LastLogOnResult;
private DateTime LastLogonSessionReplaced;
private bool LibraryLocked;
private byte LoginFailures;
private ulong MasterChatGroupID;
#pragma warning disable CA2213 // False positive, .NET Framework can't understand DisposeAsync()
@@ -259,7 +258,6 @@ public sealed class Bot : IAsyncDisposable {
private bool SteamParentalActive;
private SteamSaleEvent? SteamSaleEvent;
private string? TwoFactorCode;
private byte TwoFactorCodeFailures;
private Bot(string botName, BotConfig botConfig, BotDatabase botDatabase) {
BotName = !string.IsNullOrEmpty(botName) ? botName : throw new ArgumentNullException(nameof(botName));
@@ -860,13 +858,20 @@ public sealed class Bot : IAsyncDisposable {
switch (inputType) {
case ASF.EUserInputType.Login:
BotConfig.SteamLogin = inputValue;
// Do not allow saving this account credential
BotConfig.IsSteamLoginSet = false;
break;
case ASF.EUserInputType.Password:
BotConfig.SetDecryptedSteamPassword(inputValue);
BotConfig.SteamPassword = inputValue;
// Do not allow saving this account credential
BotConfig.IsSteamPasswordSet = false;
// If by any chance user has wrongly configured password format, we reset it back to plaintext
BotConfig.PasswordFormat = ArchiCryptoHelper.ECryptoMethod.PlainText;
break;
case ASF.EUserInputType.SteamGuard:
if (inputValue.Length != 5) {
@@ -882,6 +887,8 @@ public sealed class Bot : IAsyncDisposable {
}
BotConfig.SteamParentalCode = inputValue;
// Do not allow saving this account credential
BotConfig.IsSteamParentalCodeSet = false;
break;
@@ -2737,6 +2744,7 @@ public sealed class Bot : IAsyncDisposable {
break;
case EResult.AccountLogonDenied:
case EResult.InvalidLoginAuthCode:
RequiredInput = ASF.EUserInputType.SteamGuard;
string? authCode = await Logging.GetUserInput(ASF.EUserInputType.SteamGuard, BotName).ConfigureAwait(false);
@@ -2749,18 +2757,17 @@ public sealed class Bot : IAsyncDisposable {
}
break;
case EResult.AccountLoginDeniedNeedTwoFactor:
if (!HasMobileAuthenticator) {
RequiredInput = ASF.EUserInputType.TwoFactorAuthentication;
case EResult.AccountLoginDeniedNeedTwoFactor when !HasMobileAuthenticator:
case EResult.TwoFactorCodeMismatch when !HasMobileAuthenticator:
RequiredInput = ASF.EUserInputType.TwoFactorAuthentication;
string? twoFactorCode = await Logging.GetUserInput(ASF.EUserInputType.TwoFactorAuthentication, BotName).ConfigureAwait(false);
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!)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(twoFactorCode)));
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
if (string.IsNullOrEmpty(twoFactorCode) || !SetUserInput(ASF.EUserInputType.TwoFactorAuthentication, twoFactorCode!)) {
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(twoFactorCode)));
Stop();
}
Stop();
}
break;
@@ -2771,7 +2778,7 @@ public sealed class Bot : IAsyncDisposable {
ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.BotLoggedOn, $"{SteamID}{(!string.IsNullOrEmpty(callback.VanityURL) ? $"/{callback.VanityURL}" : "")}"));
// Old status for these doesn't matter, we'll update them if needed
InvalidPasswordFailures = TwoFactorCodeFailures = 0;
LoginFailures = 0;
LibraryLocked = PlayingBlocked = false;
if (PlayingWasBlocked && (PlayingWasBlockedTimer == null)) {
@@ -2888,6 +2895,7 @@ public sealed class Bot : IAsyncDisposable {
await PluginsCore.OnBotLoggedOn(this).ConfigureAwait(false);
break;
case EResult.AccountLoginDeniedNeedTwoFactor:
case EResult.InvalidPassword:
case EResult.NoConnection:
case EResult.PasswordRequiredToKickSession: // Not sure about this one, it seems to be just generic "try again"? #694
@@ -2899,23 +2907,24 @@ public sealed class Bot : IAsyncDisposable {
ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.BotUnableToLogin, callback.Result, callback.ExtendedResult));
switch (callback.Result) {
case EResult.InvalidPassword when string.IsNullOrEmpty(BotDatabase.LoginKey) && (++InvalidPasswordFailures >= MaxInvalidPasswordFailures):
InvalidPasswordFailures = 0;
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.BotInvalidPasswordDuringLogin, MaxInvalidPasswordFailures));
Stop();
break;
case EResult.TwoFactorCodeMismatch when HasMobileAuthenticator:
case EResult.AccountLoginDeniedNeedTwoFactor:
case EResult.TwoFactorCodeMismatch:
// There is a possibility that our cached time is no longer appropriate, so we should reset the cache in this case in order to fetch it upon the next login attempt
// Yes, this might as well be just invalid 2FA credentials, but we can't be sure about that, and we have MaxTwoFactorCodeFailures designed to verify that for us
// Yes, this might as well be just invalid 2FA credentials, but we can't be sure about that, and we have LoginFailures designed to verify that for us
await MobileAuthenticator.ResetSteamTimeDifference().ConfigureAwait(false);
if (++TwoFactorCodeFailures >= MaxTwoFactorCodeFailures) {
TwoFactorCodeFailures = 0;
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.BotInvalidAuthenticatorDuringLogin, MaxTwoFactorCodeFailures));
if (++LoginFailures >= MaxLoginFailures) {
LoginFailures = 0;
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.BotInvalidAuthenticatorDuringLogin, MaxLoginFailures));
Stop();
}
break;
case EResult.InvalidPassword when string.IsNullOrEmpty(BotDatabase.LoginKey) && (++LoginFailures >= MaxLoginFailures):
LoginFailures = 0;
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.BotInvalidPasswordDuringLogin, MaxLoginFailures));
Stop();
break;
}
@@ -2943,7 +2952,7 @@ public sealed class Bot : IAsyncDisposable {
string? loginKey = callback.LoginKey;
if (BotConfig.PasswordFormat != ArchiCryptoHelper.ECryptoMethod.PlainText) {
if (BotConfig.PasswordFormat.HasTransformation()) {
loginKey = ArchiCryptoHelper.Encrypt(BotConfig.PasswordFormat, loginKey);
}

View File

@@ -196,7 +196,8 @@ public sealed class Trading : IDisposable {
// Neutrality can't reach value below 0 at any single point of calculation, as that would imply a loss of progress even if we'd end up with a positive value by the end
int neutrality = 0;
for (byte i = 0; i < afterAmounts.Count; i++) {
// Skip initial 0 index, as we already checked it above and it doesn't change neutrality from 0
for (byte i = 1; i < afterAmounts.Count; i++) {
// We assume that the difference between amounts will be within int range, therefore we accept underflow here (for subtraction), and since we cast that result to int afterwards, we also accept overflow for the cast itself
neutrality += unchecked((int) (afterAmounts[i] - beforeAmounts[i]));

View File

@@ -509,7 +509,8 @@ public sealed class ArchiHandler : ClientMsgHandler {
ClientMsgProtobuf<CMsgClientGamesPlayed> request = new(EMsg.ClientGamesPlayedWithDataBlob) {
Body = {
client_os_type = (uint) Bot.OSType
// Underflow here is to be expected, this is Steam's logic
client_os_type = unchecked((uint) Bot.OSType)
}
};

View File

@@ -92,6 +92,13 @@ public sealed class ArchiWebHandler : IDisposable {
CachedAccessToken = new ArchiCacheable<string>(ResolveAccessToken);
WebBrowser = new WebBrowser(bot.ArchiLogger, ASF.GlobalConfig?.WebProxy);
// Report proper time when doing timezone-based calculations, see setTimezoneCookies() from https://steamcommunity-a.akamaihd.net/public/shared/javascript/shared_global.js
string timeZoneOffset = $"{DateTimeOffset.Now.Offset.TotalSeconds}{Uri.EscapeDataString(",")}0";
WebBrowser.CookieContainer.Add(new Cookie("timezoneOffset", timeZoneOffset, "/", $".{SteamCommunityURL.Host}"));
WebBrowser.CookieContainer.Add(new Cookie("timezoneOffset", timeZoneOffset, "/", $".{SteamHelpURL.Host}"));
WebBrowser.CookieContainer.Add(new Cookie("timezoneOffset", timeZoneOffset, "/", $".{SteamStoreURL.Host}"));
}
public void Dispose() {
@@ -1395,51 +1402,9 @@ public sealed class ArchiWebHandler : IDisposable {
throw new ArgumentOutOfRangeException(nameof(tradeID));
}
(bool success, string? steamApiKey) = await CachedApiKey.GetValue().ConfigureAwait(false);
Uri request = new(SteamCommunityURL, $"/tradeoffer/{tradeID}/decline");
if (!success || string.IsNullOrEmpty(steamApiKey)) {
return false;
}
Dictionary<string, object?> arguments = new(2, StringComparer.Ordinal) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
{ "key", steamApiKey! },
{ "tradeofferid", tradeID }
};
KeyValue? response = null;
for (byte i = 0; (i < WebBrowser.MaxTries) && (response == null); i++) {
if ((i > 0) && (WebLimiterDelay > 0)) {
await Task.Delay(WebLimiterDelay).ConfigureAwait(false);
}
using WebAPI.AsyncInterface econService = Bot.SteamConfiguration.GetAsyncWebAPIInterface(EconService);
econService.Timeout = WebBrowser.Timeout;
try {
response = await WebLimitRequest(
WebAPI.DefaultBaseAddress,
// ReSharper disable once AccessToDisposedClosure
async () => await econService.CallAsync(HttpMethod.Post, "DeclineTradeOffer", args: arguments).ConfigureAwait(false)
).ConfigureAwait(false);
} catch (TaskCanceledException e) {
Bot.ArchiLogger.LogGenericDebuggingException(e);
} catch (Exception e) {
Bot.ArchiLogger.LogGenericWarningException(e);
}
}
if (response == null) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries));
return false;
}
return true;
return await UrlPostWithSession(request).ConfigureAwait(false);
}
internal HttpClient GenerateDisposableHttpClient() => WebBrowser.GenerateDisposableHttpClient();
@@ -2216,13 +2181,6 @@ public sealed class ArchiWebHandler : IDisposable {
WebBrowser.CookieContainer.Add(new Cookie("steamLoginSecure", steamLoginSecure, "/", $".{SteamHelpURL.Host}"));
WebBrowser.CookieContainer.Add(new Cookie("steamLoginSecure", steamLoginSecure, "/", $".{SteamStoreURL.Host}"));
// Report proper time when doing timezone-based calculations, see setTimezoneCookies() from https://steamcommunity-a.akamaihd.net/public/shared/javascript/shared_global.js
string timeZoneOffset = $"{DateTimeOffset.Now.Offset.TotalSeconds}{Uri.EscapeDataString(",")}0";
WebBrowser.CookieContainer.Add(new Cookie("timezoneOffset", timeZoneOffset, "/", $".{SteamCommunityURL.Host}"));
WebBrowser.CookieContainer.Add(new Cookie("timezoneOffset", timeZoneOffset, "/", $".{SteamHelpURL.Host}"));
WebBrowser.CookieContainer.Add(new Cookie("timezoneOffset", timeZoneOffset, "/", $".{SteamStoreURL.Host}"));
Bot.ArchiLogger.LogGenericInfo(Strings.Success);
// Unlock Steam Parental if needed

View File

@@ -196,7 +196,7 @@ public sealed class BotConfig {
public EPersonaState OnlineStatus { get; private set; } = DefaultOnlineStatus;
[JsonProperty(Required = Required.DisallowNull)]
public ArchiCryptoHelper.ECryptoMethod PasswordFormat { get; private set; } = DefaultPasswordFormat;
public ArchiCryptoHelper.ECryptoMethod PasswordFormat { get; internal set; } = DefaultPasswordFormat;
[JsonProperty(Required = Required.DisallowNull)]
public bool Paused { get; private set; } = DefaultPaused;
@@ -525,6 +525,7 @@ public sealed class BotConfig {
}
if (PasswordFormat == ArchiCryptoHelper.ECryptoMethod.PlainText) {
// We can return SteamPassword only with PlainText, as despite no transformation other password formats still require decryption process
return SteamPassword;
}
@@ -631,15 +632,6 @@ public sealed class BotConfig {
return (botConfig, json != latestJson ? latestJson : null);
}
internal void SetDecryptedSteamPassword(string? decryptedSteamPassword) {
if (!string.IsNullOrEmpty(decryptedSteamPassword) && PasswordFormat.HasTransformation()) {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
decryptedSteamPassword = ArchiCryptoHelper.Encrypt(PasswordFormat, decryptedSteamPassword!);
}
SteamPassword = decryptedSteamPassword;
}
public enum EAccess : byte {
None,
FamilySharing,

View File

@@ -28,9 +28,10 @@ namespace ArchiSteamFarm.Web.Responses;
public class BasicResponse {
[PublicAPI]
public HttpStatusCode StatusCode { get; }
public Uri FinalUri { get; }
internal readonly Uri FinalUri;
[PublicAPI]
public HttpStatusCode StatusCode { get; }
internal BasicResponse(HttpResponseMessage httpResponseMessage) {
ArgumentNullException.ThrowIfNull(httpResponseMessage);

View File

@@ -141,7 +141,12 @@ public sealed class WebBrowser : IDisposable {
}
await using (response.ConfigureAwait(false)) {
if (response.StatusCode.IsClientErrorCode()) {
if (response.StatusCode.IsRedirectionCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
// We're not handling this error, do not try again
break;
}
} else if (response.StatusCode.IsClientErrorCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
// We're not handling this error, do not try again
break;
@@ -245,7 +250,12 @@ public sealed class WebBrowser : IDisposable {
}
await using (response.ConfigureAwait(false)) {
if (response.StatusCode.IsClientErrorCode()) {
if (response.StatusCode.IsRedirectionCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
// We're not handling this error, do not try again
break;
}
} else if (response.StatusCode.IsClientErrorCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
// We're not handling this error, do not try again
break;
@@ -301,7 +311,12 @@ public sealed class WebBrowser : IDisposable {
}
await using (response.ConfigureAwait(false)) {
if (response.StatusCode.IsClientErrorCode()) {
if (response.StatusCode.IsRedirectionCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
// We're not handling this error, do not try again
break;
}
} else if (response.StatusCode.IsClientErrorCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
// We're not handling this error, do not try again
break;
@@ -373,7 +388,12 @@ public sealed class WebBrowser : IDisposable {
continue;
}
if (response.StatusCode.IsClientErrorCode()) {
if (response.StatusCode.IsRedirectionCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
// We're not handling this error, do not try again
break;
}
} else if (response.StatusCode.IsClientErrorCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
// We're not handling this error, do not try again
break;
@@ -423,6 +443,14 @@ public sealed class WebBrowser : IDisposable {
continue;
}
if (response.StatusCode.IsRedirectionCode()) {
if (requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
result = new BasicResponse(response);
}
break;
}
if (response.StatusCode.IsClientErrorCode()) {
if (requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
result = new BasicResponse(response);
@@ -477,6 +505,14 @@ public sealed class WebBrowser : IDisposable {
continue;
}
if (response.StatusCode.IsRedirectionCode()) {
if (requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
result = new BasicResponse(response);
}
break;
}
if (response.StatusCode.IsClientErrorCode()) {
if (requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
result = new BasicResponse(response);
@@ -531,7 +567,12 @@ public sealed class WebBrowser : IDisposable {
}
await using (response.ConfigureAwait(false)) {
if (response.StatusCode.IsClientErrorCode()) {
if (response.StatusCode.IsRedirectionCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
// We're not handling this error, do not try again
break;
}
} else if (response.StatusCode.IsClientErrorCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
// We're not handling this error, do not try again
break;
@@ -587,7 +628,12 @@ public sealed class WebBrowser : IDisposable {
}
await using (response.ConfigureAwait(false)) {
if (response.StatusCode.IsClientErrorCode()) {
if (response.StatusCode.IsRedirectionCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
// We're not handling this error, do not try again
break;
}
} else if (response.StatusCode.IsClientErrorCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
// We're not handling this error, do not try again
break;
@@ -659,7 +705,12 @@ public sealed class WebBrowser : IDisposable {
continue;
}
if (response.StatusCode.IsClientErrorCode()) {
if (response.StatusCode.IsRedirectionCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
// We're not handling this error, do not try again
break;
}
} else if (response.StatusCode.IsClientErrorCode()) {
if (!requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) {
// We're not handling this error, do not try again
break;
@@ -805,7 +856,12 @@ public sealed class WebBrowser : IDisposable {
}
// WARNING: We still have not disposed response by now, make sure to dispose it ASAP if we're not returning it!
if (response.StatusCode is >= HttpStatusCode.Ambiguous and < HttpStatusCode.BadRequest && (maxRedirections > 0)) {
if (response.StatusCode.IsRedirectionCode() && (maxRedirections > 0)) {
if (requestOptions.HasFlag(ERequestOptions.ReturnRedirections)) {
// User wants to handle it manually, that's alright
return response;
}
Uri? redirectUri = response.Headers.Location;
if (redirectUri == null) {
@@ -897,6 +953,7 @@ public sealed class WebBrowser : IDisposable {
public enum ERequestOptions : byte {
None = 0,
ReturnClientErrors = 1,
ReturnServerErrors = 2
ReturnServerErrors = 2,
ReturnRedirections = 4
}
}

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>5.2.5.4</Version>
<Version>5.2.6.2</Version>
</PropertyGroup>
<PropertyGroup>
@@ -16,7 +16,7 @@
<LangVersion>latest</LangVersion>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<NeutralLanguage>en</NeutralLanguage>
<NoWarn>1591</NoWarn>
<NoWarn>1591,NU1507</NoWarn>
<Nullable>enable</Nullable>
<PackageIcon>../resources/ASF.ico</PackageIcon>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
@@ -33,6 +33,7 @@
<ItemGroup Condition="'$(TargetFramework)' == 'net48'">
<PackageReference Include="JustArchiNET.Madness" />
<Using Include="JustArchiNET.Madness" />
<Using Include="JustArchiNET.Madness.ArgumentNullExceptionMadness.ArgumentNullException" Alias="ArgumentNullException" />
<Using Include="JustArchiNET.Madness.ArrayMadness.Array" Alias="Array" />

View File

@@ -1,17 +1,17 @@
<Project>
<ItemGroup>
<PackageVersion Include="AngleSharp.XPath" Version="1.1.7" />
<PackageVersion Include="ConfigureAwaitChecker.Analyzer" Version="5.0.0" />
<PackageVersion Include="ConfigureAwaitChecker.Analyzer" Version="5.0.0.1" />
<PackageVersion Include="CryptSharpStandard" Version="1.0.0" />
<PackageVersion Include="Humanizer" Version="2.14.1" />
<PackageVersion Include="JetBrains.Annotations" Version="2022.1.0" />
<PackageVersion Include="Markdig.Signed" Version="0.30.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageVersion Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageVersion Include="MSTest.TestFramework" Version="2.2.8" />
<PackageVersion Include="Markdig.Signed" Version="0.30.2" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageVersion Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageVersion Include="MSTest.TestFramework" Version="2.2.10" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.1" />
<PackageVersion Include="Nito.AsyncEx.Coordination" Version="5.1.2" />
<PackageVersion Include="NLog.Web.AspNetCore" Version="4.14.0" />
<PackageVersion Include="NLog.Web.AspNetCore" Version="5.0.0" />
<PackageVersion Include="SteamKit2" Version="2.4.1" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.3.1" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.3.1" />
@@ -36,7 +36,7 @@
<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.24" />
<PackageVersion Include="Microsoft.Extensions.Logging.Configuration" Version="3.1.24" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="3.1.25" />
<PackageVersion Include="Microsoft.Extensions.Logging.Configuration" Version="3.1.25" />
</ItemGroup>
</Project>

2
wiki

Submodule wiki updated: 6977556703...8beb1e38d6