Skip to content

Commit

Permalink
Protect RefreshWebSession with a semaphore
Browse files Browse the repository at this point in the history
  • Loading branch information
JustArchi committed Oct 20, 2023
1 parent 1f26071 commit 93402cc
Showing 1 changed file with 45 additions and 32 deletions.
77 changes: 45 additions & 32 deletions ArchiSteamFarm/Steam/Bot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
private readonly SemaphoreSlim InitializationSemaphore = new(1, 1);
private readonly SemaphoreSlim MessagingSemaphore = new(1, 1);
private readonly ConcurrentDictionary<UserNotificationsCallback.EUserNotification, uint> PastNotifications = new();
private readonly SemaphoreSlim RefreshWebSessionSemaphore = new(1, 1);
private readonly SemaphoreSlim SendCompleteTypesSemaphore = new(1, 1);
private readonly SteamClient SteamClient;
private readonly ConcurrentHashSet<ulong> SteamFamilySharingIDs = new();
Expand Down Expand Up @@ -376,6 +377,7 @@ public void Dispose() {
GamesRedeemerInBackgroundSemaphore.Dispose();
InitializationSemaphore.Dispose();
MessagingSemaphore.Dispose();
RefreshWebSessionSemaphore.Dispose();
SendCompleteTypesSemaphore.Dispose();
Trading.Dispose();

Expand All @@ -401,6 +403,7 @@ public async ValueTask DisposeAsync() {
GamesRedeemerInBackgroundSemaphore.Dispose();
InitializationSemaphore.Dispose();
MessagingSemaphore.Dispose();
RefreshWebSessionSemaphore.Dispose();
SendCompleteTypesSemaphore.Dispose();
Trading.Dispose();

Expand Down Expand Up @@ -1532,55 +1535,65 @@ internal async Task<bool> RefreshWebSession(bool force = false) {
return false;
}

DateTime now = DateTime.UtcNow;
await RefreshWebSessionSemaphore.WaitAsync().ConfigureAwait(false);

if (!force && !string.IsNullOrEmpty(AccessToken) && AccessTokenValidUntil.HasValue && (AccessTokenValidUntil.Value > now.AddMinutes(MinimumAccessTokenValidityMinutes))) {
// We can use the tokens we already have
if (await ArchiWebHandler.Init(SteamID, SteamClient.Universe, AccessToken!, SteamParentalActive ? BotConfig.SteamParentalCode : null).ConfigureAwait(false)) {
InitRefreshTokensTimer(AccessTokenValidUntil.Value);
try {
if (!IsConnectedAndLoggedOn) {
return false;
}

return true;
DateTime now = DateTime.UtcNow;

if (!force && !string.IsNullOrEmpty(AccessToken) && AccessTokenValidUntil.HasValue && (AccessTokenValidUntil.Value > now.AddMinutes(MinimumAccessTokenValidityMinutes))) {
// We can use the tokens we already have
if (await ArchiWebHandler.Init(SteamID, SteamClient.Universe, AccessToken!, SteamParentalActive ? BotConfig.SteamParentalCode : null).ConfigureAwait(false)) {
InitRefreshTokensTimer(AccessTokenValidUntil.Value);

return true;
}
}
}

// We need to refresh our session, access token is no longer valid
BotDatabase.AccessToken = AccessToken = null;
// We need to refresh our session, access token is no longer valid
BotDatabase.AccessToken = AccessToken = null;

if (string.IsNullOrEmpty(RefreshToken)) {
// Without refresh token we can't get fresh access tokens, relog needed
await Connect(true).ConfigureAwait(false);
if (string.IsNullOrEmpty(RefreshToken)) {
// Without refresh token we can't get fresh access tokens, relog needed
await Connect(true).ConfigureAwait(false);

return false;
}
return false;
}

CAuthentication_AccessToken_GenerateForApp_Response? response = await ArchiHandler.GenerateAccessTokens(RefreshToken!).ConfigureAwait(false);
CAuthentication_AccessToken_GenerateForApp_Response? response = await ArchiHandler.GenerateAccessTokens(RefreshToken!).ConfigureAwait(false);

if (string.IsNullOrEmpty(response?.access_token)) {
// The request has failed, in almost all cases this means our refresh token is no longer valid, relog needed
BotDatabase.RefreshToken = RefreshToken = null;
if (string.IsNullOrEmpty(response?.access_token)) {
// The request has failed, in almost all cases this means our refresh token is no longer valid, relog needed
BotDatabase.RefreshToken = RefreshToken = null;

ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(ArchiHandler.GenerateAccessTokens)));
ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(ArchiHandler.GenerateAccessTokens)));

await Connect(true).ConfigureAwait(false);
await Connect(true).ConfigureAwait(false);

return false;
}
return false;
}

// TODO: Handle update of refresh token with next SK2 release
UpdateTokens(response.access_token, RefreshToken!);
// TODO: Handle update of refresh token with next SK2 release
UpdateTokens(response.access_token!, RefreshToken!);

Check warning on line 1580 in ArchiSteamFarm/Steam/Bot.cs

View workflow job for this annotation

GitHub Actions / main (Debug, windows-latest)

Dereference of a possibly null reference.

Check warning on line 1580 in ArchiSteamFarm/Steam/Bot.cs

View workflow job for this annotation

GitHub Actions / main (Debug, windows-latest)

Dereference of a possibly null reference.

Check failure on line 1580 in ArchiSteamFarm/Steam/Bot.cs

View workflow job for this annotation

GitHub Actions / main (Release, windows-latest)

Dereference of a possibly null reference.

Check failure on line 1580 in ArchiSteamFarm/Steam/Bot.cs

View workflow job for this annotation

GitHub Actions / main (Release, windows-latest)

Dereference of a possibly null reference.

Check failure on line 1580 in ArchiSteamFarm/Steam/Bot.cs

View workflow job for this annotation

GitHub Actions / publish-asf (windows-latest, generic-netf)

Dereference of a possibly null reference.

Check failure on line 1580 in ArchiSteamFarm/Steam/Bot.cs

View workflow job for this annotation

GitHub Actions / publish-asf (windows-latest, generic-netf)

Dereference of a possibly null reference.

if (await ArchiWebHandler.Init(SteamID, SteamClient.Universe, response.access_token, SteamParentalActive ? BotConfig.SteamParentalCode : null).ConfigureAwait(false)) {
InitRefreshTokensTimer(AccessTokenValidUntil ?? now.AddDays(1));
if (await ArchiWebHandler.Init(SteamID, SteamClient.Universe, response.access_token!, SteamParentalActive ? BotConfig.SteamParentalCode : null).ConfigureAwait(false)) {
InitRefreshTokensTimer(AccessTokenValidUntil ?? now.AddHours(18));

return true;
}
return true;
}

// We got the tokens, but failed to authorize? Purge them just to be sure and reconnect
BotDatabase.AccessToken = AccessToken = null;
// We got the tokens, but failed to authorize? Purge them just to be sure and reconnect
BotDatabase.AccessToken = AccessToken = null;

await Connect(true).ConfigureAwait(false);
await Connect(true).ConfigureAwait(false);

return false;
return false;
} finally {
RefreshWebSessionSemaphore.Release();
}
}

internal static async Task RegisterBot(string botName) {
Expand Down

0 comments on commit 93402cc

Please sign in to comment.